aboutsummaryrefslogtreecommitdiff
path: root/core/strings
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2019-01-06 22:11:45 +0000
committergingerBill <bill@gingerbill.org>2019-01-06 22:11:45 +0000
commit64f84ef9a32b4e24374adc91abffa0104778be1e (patch)
treed48d44ca03e319c9023808d5a1aaa2291461511e /core/strings
parentd1b9f3ac74df5533f1857a26831419aeb560fd2f (diff)
fmt.printf("%q", str); (quotes strings)
Diffstat (limited to 'core/strings')
-rw-r--r--core/strings/builder.odin88
1 files changed, 75 insertions, 13 deletions
diff --git a/core/strings/builder.odin b/core/strings/builder.odin
index c79352719..389030ba4 100644
--- a/core/strings/builder.odin
+++ b/core/strings/builder.odin
@@ -62,25 +62,25 @@ write_bytes :: proc(b: ^Builder, x: []byte) {
}
-write_encoded_rune :: proc(b: ^Builder, r: rune) {
- write_byte(b, '\'');
+write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) {
+ if write_quote do write_byte(b, '\'');
switch r {
- case '\a': write_string(b, "\\a");
- case '\b': write_string(b, "\\b");
- case '\e': write_string(b, "\\e");
- case '\f': write_string(b, "\\f");
- case '\n': write_string(b, "\\n");
- case '\r': write_string(b, "\\r");
- case '\t': write_string(b, "\\t");
- case '\v': write_string(b, "\\v");
+ case '\a': write_string(b, `\a"`);
+ case '\b': write_string(b, `\b"`);
+ case '\e': write_string(b, `\e"`);
+ case '\f': write_string(b, `\f"`);
+ case '\n': write_string(b, `\n"`);
+ case '\r': write_string(b, `\r"`);
+ case '\t': write_string(b, `\t"`);
+ case '\v': write_string(b, `\v"`);
case:
if r < 32 {
- write_string(b, "\\x");
+ write_string(b, `\x`);
buf: [2]byte;
s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil);
switch len(s) {
case 0: write_string(b, "00");
- case 1: write_rune(b, '0');
+ case 1: write_byte(b, '0');
case 2: write_string(b, s);
}
} else {
@@ -88,7 +88,69 @@ write_encoded_rune :: proc(b: ^Builder, r: rune) {
}
}
- write_byte(b, '\'');
+ if write_quote do write_byte(b, '\'');
+}
+
+
+write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte) {
+ static DIGITS_LOWER := "0123456789abcdefx";
+
+ is_printable :: proc(r: rune) -> bool {
+ if r <= 0xff {
+ switch r {
+ case 0x20..0x7e:
+ return true;
+ case 0xa1..0xff: // ¡ through ÿ except for the soft hyphen
+ return r != 0xad; //
+ }
+ }
+
+ // TODO(bill): A proper unicode library will be needed!
+ return false;
+ }
+
+ if r == rune(quote) || r == '\\' {
+ write_byte(b, '\\');
+ write_byte(b, byte(r));
+ return;
+ } else if is_printable(r) {
+ write_encoded_rune(b, r, false);
+ return;
+ }
+ switch r {
+ case '\a': write_string(b, `\a`);
+ case '\b': write_string(b, `\b`);
+ case '\e': write_string(b, `\e`);
+ case '\f': write_string(b, `\f`);
+ case '\n': write_string(b, `\n`);
+ case '\r': write_string(b, `\r`);
+ case '\t': write_string(b, `\t`);
+ case '\v': write_string(b, `\v`);
+ case:
+ switch {
+ case r < ' ':
+ write_byte(b, '\\');
+ write_byte(b, 'x');
+ write_byte(b, DIGITS_LOWER[byte(r)>>4]);
+ write_byte(b, DIGITS_LOWER[byte(r)&0xf]);
+
+ case r > utf8.MAX_RUNE:
+ r = 0xfffd;
+ fallthrough;
+ case r < 0x10000:
+ write_byte(b, '\\');
+ write_byte(b, 'u');
+ for s := 12; s >= 0; s -= 4 {
+ write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
+ }
+ case:
+ write_byte(b, '\\');
+ write_byte(b, 'U');
+ for s := 28; s >= 0; s -= 4 {
+ write_byte(b, DIGITS_LOWER[r>>uint(s) & 0xf]);
+ }
+ }
+ }
}