diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2021-05-04 07:19:15 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2021-05-04 07:19:15 -0700 |
commit | f32073001a616fad05b04dd8451292350d572352 (patch) | |
tree | 8da6c8bbf5b131b5c815248cdb1ecafdf80c2fbb | |
parent | 0c07bd4a499379c47916ce7cbf8d03af79e3aa98 (diff) | |
download | txr-f32073001a616fad05b04dd8451292350d572352.tar.gz txr-f32073001a616fad05b04dd8451292350d572352.tar.bz2 txr-f32073001a616fad05b04dd8451292350d572352.zip |
format: ~x/~X specifiers support buffers.
* buf.c (buf_hex): New function.
* buf.h (buf_hex): Declared.
* stream.c (formatv): Support printing of buffers in hex
via temporary buffer containing hex characters, similarly
to how bignums are handled.
* tests/018/format.tl: New file, providing some coverage over
new and affected code.
-rw-r--r-- | buf.c | 14 | ||||
-rw-r--r-- | buf.h | 2 | ||||
-rw-r--r-- | stream.c | 48 | ||||
-rw-r--r-- | tests/018/format.tl | 29 | ||||
-rw-r--r-- | txr.1 | 9 |
5 files changed, 84 insertions, 18 deletions
@@ -834,6 +834,20 @@ val buf_pprint(val buf, val stream_in) return t; } +void buf_hex(val buf, char *hex, size_t sz, int caps) +{ + val self = lit("buf-hex"); + struct buf *b = buf_handle(buf, self); + size_t i; + unsigned char *data = b->data; + const char *fmt = caps ? "%02X" : "%02x"; + + *hex = 0; + + for (i = 0; i < sz - 1; i += 2) + hex += sprintf(hex, fmt, *data++); +} + struct buf_strm { struct strm_base a; utf8_decoder_t ud; @@ -113,6 +113,8 @@ val buf_get_cptr(val buf, val pos); val buf_print(val buf, val stream); val buf_pprint(val buf, val stream); +void buf_hex(val buf, char *, size_t, int); + val make_buf_stream(val buf_opt); val get_buf_from_stream(val stream); @@ -3407,19 +3407,41 @@ val formatv(val stream_in, val fmtstr, struct args *al) obj = args_get_checked(self, al, &arg_ix); typ = type(obj); hex: - if (typ == BGNUM) { - int nchars = mp_radix_size(mp(obj), 16); - if (nchars >= convert(int, sizeof (num_buf))) - pnum = coerce(char *, chk_malloc(nchars + 1)); - mp_toradix_case(mp(obj), coerce(unsigned char *, pnum), 16, ch == 'x'); - } else { - const char *fmt = ch == 'x' ? num_fmt->hex : num_fmt->HEX; - value = c_num(obj, self); - if (value < 0) { - num_buf[0] = '-'; - sprintf(num_buf + 1, fmt, -value); - } else { - sprintf(num_buf, fmt, value); + switch (typ) { + case BGNUM: + { + int nchars = mp_radix_size(mp(obj), 16); + if (nchars >= convert(int, sizeof (num_buf))) + pnum = coerce(char *, chk_malloc(nchars + 1)); + mp_toradix_case(mp(obj), coerce(unsigned char *, pnum), 16, ch == 'x'); + } + break; + case BUF: + { + ucnum len = c_unum(length_buf(obj), self); + ucnum nchars = 2 * len + 1; + + if (len >= INT_PTR_MAX) + uw_throwf(error_s, lit("~a: ~~~a conversion given " + "too large a buf argument"), + self, chr(ch), nao); + + pnum = coerce(char *, chk_malloc(nchars)); + buf_hex(obj, pnum, nchars, ch == 'X'); + } + break; + case NUM: + case CHR: + default: + { + const char *fmt = ch == 'x' ? num_fmt->hex : num_fmt->HEX; + value = c_num(obj, self); + if (value < 0) { + num_buf[0] = '-'; + sprintf(num_buf + 1, fmt, -value); + } else { + sprintf(num_buf, fmt, value); + } } } goto output_num; diff --git a/tests/018/format.tl b/tests/018/format.tl new file mode 100644 index 00000000..3e9e4f5b --- /dev/null +++ b/tests/018/format.tl @@ -0,0 +1,29 @@ +(load "../common") + +(mtest + (fmt "~x" #b'') "" + (fmt "~4x" #b'') " " + (fmt "~4,02x" #b'') " 00" + (fmt "~x" #b'AF') "af" + (fmt "~4x" #b'AF') " af" + (fmt "~-4x" #b'AF') "af " + (fmt "~4,03x" #b'AF') " 0af" + (fmt "~-4,03X" #b'AF') "0AF ") + +(mtest + (fmt "~x" #\xaf) "af" + (fmt "~4x" #\xaf) " af" + (fmt "~-4x" #\xaf) "af " + (fmt "~4,03x" #\xaf) " 0af" + (fmt "~-4,03X" #\xaf) "0AF ") + +(mtest + (fmt "~x" #xaf) "af" + (fmt "~4x" #xaf) " af" + (fmt "~-4x" #xaf) "af " + (fmt "~4,03x" #xaf) " 0af" + (fmt "~-4,03X" #xaf) "0AF ") + +(test + (fmt "~x" (sha256 "abc")) + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") @@ -53534,14 +53534,13 @@ Requires an argument of integer or character type type. The integer value or character code is printed in decimal. .coIP x -Requires an argument of character or integer type. The integer value or -character code is printed in hexadecimal, using lowercase letters -for the digits +Requires an argument of character, integer or buffer type. The integer value, +character code, or buffer contents are printed in hexadecimal, using lowercase +letters for the digits .code a through .codn f . -Width and precision semantics -are as described for the +Width and precision semantics are as described for the .code a format directive, for integers. |