summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-05-04 07:19:15 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-05-04 07:19:15 -0700
commitf32073001a616fad05b04dd8451292350d572352 (patch)
tree8da6c8bbf5b131b5c815248cdb1ecafdf80c2fbb
parent0c07bd4a499379c47916ce7cbf8d03af79e3aa98 (diff)
downloadtxr-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.c14
-rw-r--r--buf.h2
-rw-r--r--stream.c48
-rw-r--r--tests/018/format.tl29
-rw-r--r--txr.19
5 files changed, 84 insertions, 18 deletions
diff --git a/buf.c b/buf.c
index 5d0fb268..1804733a 100644
--- a/buf.c
+++ b/buf.c
@@ -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;
diff --git a/buf.h b/buf.h
index 1805f3b8..89c543e5 100644
--- a/buf.h
+++ b/buf.h
@@ -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);
diff --git a/stream.c b/stream.c
index 52389245..b565b57e 100644
--- a/stream.c
+++ b/stream.c
@@ -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")
diff --git a/txr.1 b/txr.1
index cbf7f97c..bbe1560d 100644
--- a/txr.1
+++ b/txr.1
@@ -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.