diff --git a/c/builtins.c b/c/builtins.c index d81b4c5..4001cdc 100644 --- a/c/builtins.c +++ b/c/builtins.c @@ -1957,10 +1957,13 @@ static Value bi_open_output_string(Value *a, int n, Env *e) { } static Value bi_get_output_string(Value *a, int n, Env *e) { (void)e; CHECK_ARITY("get-output-string", 1); - char *s = port_get_output_string(AS_PORT(a[0])); - Value r = make_string_from_cstr(s); - ul_free(s); - return r; + /* Use port's known str_len, not strlen — emitter writes binary + * (op bytes with embedded 0x00). strlen truncates at first null. */ + ULPort *p = AS_PORT(a[0]); + if (p->kind != PORT_STRING || p->dir != PORT_OUTPUT) { + return make_string("", 0, false); + } + return make_string(p->str_buf, p->str_len, false); } static Value bi_close_port(Value *a, int n, Env *e) { (void)e; CHECK_ARITY("close-port", 1); @@ -2360,6 +2363,14 @@ static Value bi_write_string(Value *a, int n, Env *e) { static Value bi_write_char(Value *a, int n, Env *e) { (void)e; CHECK_MIN_ARITY("write-char", 1); + /* Route to string-port buffer when target is a string port — without + * this, write-char ignored string ports and wrote to stdout, breaking + * binary emit through (open-output-string) accumulators. */ + if (n > 1 && IS_PORT(a[1]) && AS_PORT(a[1])->kind == PORT_STRING) { + char ch = (char)AS_CHAR(a[0]); + port_write_str(AS_PORT(a[1]), &ch, 1); + return VAL_VOID; + } FILE *out = n > 1 && IS_PORT(a[1]) ? AS_PORT(a[1])->fp : stdout; fputc(AS_CHAR(a[0]), out ? out : stdout); fflush(out ? out : stdout);