std/io.zc
Rama main · réplica de lectura del repositorio original.
import "./core.zc"
import "./mem.zc"
import "./string.zc"
include <stdio.h>
include <stdarg.h>
/// Formats into a thread-local buffer (ring of buffers for nesting).
fn format(fmt: char*, ...) -> char* {
// A small ring of thread-local buffers so nested format() calls (e.g.
// format("%s", format("%d", x))) do not clobber each other. Each returned
// pointer stays valid until 4 further format() calls on the same thread.
@thread_local static let buffer0: char[4096];
@thread_local static let buffer1: char[4096];
@thread_local static let buffer2: char[4096];
@thread_local static let buffer3: char[4096];
@thread_local static let slot: int = 0;
let idx = slot;
slot = (slot + 1) % 4;
let buf: char* = NULL;
if (idx == 0) {
buf = (char*)buffer0;
} else if (idx == 1) {
buf = (char*)buffer1;
} else if (idx == 2) {
buf = (char*)buffer2;
} else {
buf = (char*)buffer3;
}
let ap: va_list;
va_start(ap, fmt);
vsnprintf(buf, 4096, fmt, ap);
va_end(ap);
return buf;
}
/// Formats into a caller-provided buffer.
fn format_into(buffer: char*, size: usize, fmt: char*, ...) -> c_int {
let ap: va_list;
va_start(ap, fmt);
let ret = vsnprintf(buffer, size, fmt, ap);
va_end(ap);
return ret;
}
/// Formats into a new heap-allocated buffer (caller frees).
fn format_new(fmt: char*, ...) -> char* {
let buffer: char* = alloc_n<char>(1024);
if buffer == NULL return NULL;
let ap: va_list;
va_start(ap, fmt);
vsnprintf(buffer, 1024, fmt, ap);
va_end(ap);
return buffer;
}
/// Prints formatted output to stdout.
fn print(fmt: char*, ...) -> c_int {
let ap: va_list;
va_start(ap, fmt);
let ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
/// Prints formatted output to stdout followed by a newline.
fn println(fmt: char*, ...) -> c_int {
let ap: va_list;
va_start(ap, fmt);
let ret = vprintf(fmt, ap);
va_end(ap);
puts("");
return ret + 1;
}
/// Reads a line from stdin (caller frees).
fn readln() -> char* {
let cap: usize = 64;
let len: usize = 0;
let line: char* = alloc_n<char>(cap);
if (line == NULL) {
return NULL;
}
let c: c_int;
let std_in = stdin;
while (true) {
c = fgetc((FILE*)std_in);
// Explicit cast to avoid -1 becoming UINT64_MAX in some contexts if treated as unsigned
let eof_c: c_int = -1;
if (c == eof_c) {
break;
}
let nl_c: c_int = 10;
if (c == nl_c) {
break; // '\n'
}
if (len + 1 >= cap) {
cap = cap * 2;
let n = realloc_n<char>(line, cap / 2, cap);
if (n == NULL) {
dealloc<char>(line);
return NULL;
}
line = n;
}
line[len] = c;
len = len + 1;
}
let eof_final: int = -1;
if (len == 0 && c == eof_final) {
dealloc<char>(line);
return NULL;
}
line[len] = 0;
return line;
}
fn _utf8_seq_len(first_byte: byte) -> usize {
let b = (int)first_byte;
if ((b & 0x80) == 0) { return 1; } // 0xxxxxxx
if ((b & 0xE0) == 0xC0) { return 2; } // 110xxxxx
if ((b & 0xF0) == 0xE0) { return 3; } // 1110xxxx
if ((b & 0xF8) == 0xF0) { return 4; } // 11110xxx
return 1; // Fallback
}
/// Reads a single rune from stdin.
fn read_rune() -> rune {
let std_in = stdin;
let c1 = fgetc((FILE*)std_in);
if (c1 == -1) {
return (rune)0;
}
let first = (byte)c1;
let len = _utf8_seq_len(first);
if (len == 1) {
return (rune)first;
}
let val: uint32_t = 0;
if (len == 2) {
val = (uint32_t)(first & 0x1F) << 6;
val = val | (uint32_t)((byte)fgetc((FILE*)std_in) & 0x3F);
} else if (len == 3) {
val = (uint32_t)(first & 0x0F) << 12;
val = val | ((uint32_t)((byte)fgetc((FILE*)std_in) & 0x3F) << 6);
val = val | (uint32_t)((byte)fgetc((FILE*)std_in) & 0x3F);
} else if (len == 4) {
val = (uint32_t)(first & 0x07) << 18;
val = val | ((uint32_t)((byte)fgetc((FILE*)std_in) & 0x3F) << 12);
val = val | ((uint32_t)((byte)fgetc((FILE*)std_in) & 0x3F) << 6);
val = val | (uint32_t)((byte)fgetc((FILE*)std_in) & 0x3F);
}
return (rune)val;
}
// Integer to string conversion
/// Converts an int to a string in a static buffer.
fn itos(n: int) -> char* {
@thread_local static let buffer: char[32];
sprintf((char*)buffer, "%d", n);
return (char*)buffer;
}
// Heap-allocated integer to string - caller must free
/// Converts an int to a heap-allocated string (caller frees).
fn itos_new(n: int) -> char* {
let buffer: char* = alloc_n<char>(32);
if (buffer == NULL) {
return NULL;
}
sprintf(buffer, "%d", n);
return buffer;
}
// Unsigned integer to string
/// Converts an unsigned int to a string in a static buffer.
fn utos(n: u32) -> char* {
@thread_local static let buffer: char[32];
sprintf((char*)buffer, "%u", n);
return (char*)buffer;
}