Ctrl K
ComunidadGuías…

std/io.zc

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot

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;
}