lib/fmt: encode rune args as UTF-8, not a truncated low byte (#66)
writeone and formatraw's rune arm did `buf[0] = r: u8; putbytes(...,1)`, emitting only the low byte — invalid UTF-8 for any rune > 0x7F, with a success return. rawlen's rune arm hardcoded 1, desyncing width-padding for multibyte runes. Route both write arms through utf8.encoderune and rawlen through utf8.runesz (ref/hare/fmt/print.ha:84). Uses the current in-tree encoderune(out: []u8, r) caller-buffer signature; report-#168's signature realignment is a separate item, not folded here. fmttest gains fprintrune (1/2/3/4-byte runes) + fprintf_rune_width (multibyte pad).
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
package fmt;
|
||||
|
||||
import io;
|
||||
import encoding.utf8;
|
||||
import math;
|
||||
import memio;
|
||||
import os;
|
||||
@@ -115,9 +116,15 @@ fn writeone(s: io.handle, a: formattable) (size | io.error) = {
|
||||
return putbytes(s, v.ptr, v.len);
|
||||
};
|
||||
case let r: rune => {
|
||||
// ref/hare/fmt/print.ha:84 io::write(out, utf8::encoderune(r)):
|
||||
// emit the full UTF-8 encoding, not the truncated low byte.
|
||||
let buf: [4]u8;
|
||||
buf[0] = r: u8;
|
||||
return putbytes(s, &buf[0], 1);
|
||||
let sl: []u8;
|
||||
sl.ptr = &buf[0];
|
||||
sl.len = 4;
|
||||
sl.cap = 4;
|
||||
let nn: i32 = utf8.encoderune(sl, r);
|
||||
return putbytes(s, &buf[0], nn);
|
||||
};
|
||||
case let v: f64 => {
|
||||
// strconv.f64tos static-buffer view consumed before next
|
||||
@@ -348,7 +355,10 @@ fn rawlen(arg: formattable, m: *mods) i32 = {
|
||||
case let v: i64 => return rawleni64(v, m);
|
||||
case let v: str => return rawlenstr(v, m);
|
||||
case let b: bool => { if (b) { return 4; }; return 5; };
|
||||
case let r: rune => return 1;
|
||||
// width-padding must count the rune's encoded byte length, else a
|
||||
// multibyte rune desyncs the pad (ref/hare/fmt/print.ha:84 emits the
|
||||
// full encoding; runesz is its length).
|
||||
case let r: rune => return utf8.runesz(r);
|
||||
case let v: f64 => return rawlenf64(v, m);
|
||||
case let v: int => return rawleni64(v: i64, m);
|
||||
case let v: uint => return rawlenu64(v: u64, m);
|
||||
@@ -412,9 +422,14 @@ fn formatraw(s: io.handle, arg: formattable, m: *mods) (size | io.error) = {
|
||||
return putbytes(s, v.ptr, v.len);
|
||||
};
|
||||
case let r: rune => {
|
||||
// ref/hare/fmt/print.ha:84: full UTF-8 encoding, not the low byte.
|
||||
let buf: [4]u8;
|
||||
buf[0] = r: u8;
|
||||
return putbytes(s, &buf[0], 1);
|
||||
let sl: []u8;
|
||||
sl.ptr = &buf[0];
|
||||
sl.len = 4;
|
||||
sl.cap = 4;
|
||||
let nn: i32 = utf8.encoderune(sl, r);
|
||||
return putbytes(s, &buf[0], nn);
|
||||
};
|
||||
case let v: f64 => {
|
||||
// strconv.f64tos prepends '-' for negative values; peel here so
|
||||
|
||||
Reference in New Issue
Block a user