diff options
-rw-r--r-- | buf.c | 24 | ||||
-rw-r--r-- | buf.h | 2 | ||||
-rw-r--r-- | eval.c | 8 | ||||
-rw-r--r-- | lib.c | 34 | ||||
-rw-r--r-- | lib.h | 1 | ||||
-rw-r--r-- | tests/012/readprint.tl | 19 | ||||
-rw-r--r-- | txr.1 | 68 |
7 files changed, 147 insertions, 9 deletions
@@ -887,6 +887,30 @@ val buf_pprint(val buf, val stream_in) return t; } +val buf_str_sep(val buf, val sep, val self) +{ + struct buf *b = buf_handle(buf, self); + ucnum len = c_unum(b->len, self); + val ret = null_string; + + if (len > 0) { + val stream = make_string_output_stream(); + ucnum i = 0; + + goto first; + + while (i < len) { + put_string(sep, stream); + first: + format(stream, lit("~,02x"), num_fast(b->data[i++]), nao); + } + + ret = get_string_from_stream(stream); + } + + return ret; +} + void buf_hex(val buf, char *hex, size_t sz, int caps) { val self = lit("buf-hex"); @@ -115,6 +115,8 @@ val buf_get_cptr(val buf, val pos); val buf_print(val buf, val stream); val buf_pprint(val buf, val stream); +val buf_str_sep(val buf, val sep, val self); + void buf_hex(val buf, char *, size_t, int); val make_buf_stream(val buf_opt); @@ -2979,14 +2979,18 @@ static val fmt_tostring(val obj) static val fmt_cat(val obj, val sep) { + val self = lit("quasistring formatting"); + switch (type(obj)) { case LIT: case STR: case LSTR: - return obj; + return if3(null_or_missing_p(sep), obj, fmt_str_sep(sep, obj, self)); case BUF: if (!opt_compat || opt_compat > 294) - return tostringp(obj); + return if3(null_or_missing_p(sep), + fmt_cat(tostringp(obj), sep), + buf_str_sep(obj, sep, self)); /* fallthrough */ default: return if3(if3(opt_compat && opt_compat <= 174, listp(obj), seqp(obj)), @@ -6237,6 +6237,40 @@ val fmt_join(varg args) return join_with(nil, args); } +val fmt_str_sep(val sep, val str, val self) +{ + ucnum lsep = c_unum(length_str(sep), self); + ucnum lstr = c_unum(length_str(str), self); + const wchar_t *csep = c_str(sep, self); + const wchar_t *cstr = c_str(str, self); + ucnum total = (lstr > 0 ? (lstr - 1) * lsep + lstr : 0) + 1; + ucnum i; + wchar_t *out = chk_wmalloc(total); + wchar_t *ptr = out, *end = out + total; + + for (i = 0; i < lstr; i++) { + if (i > 0) { + if (end - ptr <= convert(ptrdiff_t, lsep)) + break; + wcscpy(ptr, csep); + ptr += lsep; + } + if (end - ptr <= 1) + break; + *ptr++ = cstr[i]; + } + + if (i < lstr) { + free(out); + uw_throwf(error_s, lit("~a: string length overflow"), self, nao); + } + + *ptr = 0; + + return string_own(out); +} + + val split_str_keep(val str, val sep, val keep_sep_opt, val count_opt) { val self = lit("split-str"); @@ -1103,6 +1103,7 @@ val scat2(val s1, val s2); val scat3(val s1, val sep, val s2); val join_with(val sep, varg args); val fmt_join(varg args); +val fmt_str_sep(val sep, val str, val self); val split_str(val str, val sep); val split_str_keep(val str, val sep, val keep_sep_opt, val count_opt); val spl(val sep, val arg1, val arg2); diff --git a/tests/012/readprint.tl b/tests/012/readprint.tl index b3c2ff14..deebeba0 100644 --- a/tests/012/readprint.tl +++ b/tests/012/readprint.tl @@ -21,6 +21,21 @@ `@b` "abcdef" `@{b [0..1]}` "ab" `@{b [-1..:]}` "ef" - `@{b ":"}` "abcdef" - `@{b [0..2] ":"}` "abcd" + `@{b ":"}` "ab:cd:ef" + `@{b ""}` "abcdef" + `@{b [0..2] ":"}` "ab:cd" + `@{b [0..1] ":"}` "ab" + `@{b [0..0] ":"}` "" `@{b [-1]}` "239")) + +(let ((b "abcdef")) + (mtest + `@b` "abcdef" + `@{b [0..1]}` "a" + `@{b [-1..:]}` "f" + `@{b ":"}` "a:b:c:d:e:f" + `@{b ""}` "abcdef" + `@{b [0..2] ":"}` "a:b" + `@{b [0..1] ":"}` "a" + `@{b [0..0] ":"}` "" + `@{b [-1]}` "f")) @@ -9632,11 +9632,14 @@ than a list or string, it will be converted to a string as if by the .code tostring function in \*(TL. -A list is converted to a string in a special way: the elements are -individually converted to a string and then they are catenated together. -The default separator string is a single space: an alternate separation -can be specified as an argument in the brace substitution syntax. -Empty lists turn into an empty string. +A value which is a sequence is converted to a string in a special way: the +elements are individually converted to strings and then they are catenated +together. The default separator string for most sequences is a single space: +an alternate separation can be specified as an argument in the brace +substitution syntax. Empty sequences turn into an empty string. +More details are given in the +.B "Output Variables: Separation" +section below. Lists may be output within .code @(repeat) @@ -9670,6 +9673,56 @@ for the output clause. The syntax for this is The filter specification syntax is the same as in the output clause. See Output Filtering below. +.NP* Output Variables: Buffer Objects + +When the value of an output variable is a buffer (object of type +.codn buf ), +it is rendered as a sequence of hexadecimal digit pairs, with +no line breaks. The digits +.code a +through +.code f +are rendered in lower case. + +.NP* Output Variables: Separation + +As mentioned in the previous section, the value of a variable +can be a sequence. The individual elements of a sequence are turned +into strings, and then catenated together with the separator, +which may be specified as a string modifier in the variable syntax. + +For most sequences, the default separator is a space. + +When the value of a variable is a character string, and the +separator is not specified, the string is output as-is. +Effectively, the string is treated as a sequence but with an +empty default separator. + +When the value of a variable is a buffer, it is rendered in +hexadecimal, as described in the previous section. +If a separator string modifier is specified, it separates +pairs of digits, rather than individual digits. + +Example: + +.verb + @(bind str "string") + @(bind buf #b'cafef00d') + @(output) + @{str[0..3] "--"} + @{buf[0..2] ":"} + @{buf[2..4] "/"} + @(end) +.brev + +The above example produces the output + +.verb + s--t--r + ca:fe + f0/0d +.brev + .NP* Output Variables: Indexing Additional syntax is supported in output variables that does not appear @@ -9725,6 +9778,11 @@ separator string, and .code 10 specifies the field width. +When a variable includes indexing, separation and a field width, +the indexing operation is first applied to select a subsequence. +Then separation is applied to produce a textual representation. +Finally the representation is rendered din the specified field width. + .NP* Output Substitutions The brace syntax has another syntactic and semantic extension in |