#include #include typedef unsigned long clio_size_t; #define CLIO_SINK_FD 1 #define CLIO_SINK_BUF 2 struct clio_sink { int mode; int fd; char *buffer; clio_size_t capacity; clio_size_t count; int failed; }; static clio_size_t clio_strlen(const char *text) { clio_size_t len = 0UL; if (text == (const char *)0) { return 0UL; } while (text[len] != '\0') { len++; } return len; } static int clio_write_all_fd(int fd, const char *text, clio_size_t len) { const char *cursor = text; clio_size_t left = len; if (fd < 0 || (text == (const char *)0 && len != 0UL)) { return EOF; } while (left > 0UL) { u64 wrote = cleonos_sys_fd_write((u64)fd, cursor, (u64)left); clio_size_t progressed; if (wrote == 0ULL || wrote == (u64)-1) { return EOF; } progressed = (wrote > (u64)left) ? left : (clio_size_t)wrote; cursor += progressed; left -= progressed; } if (len > 0x7FFFFFFFUL) { return 0x7FFFFFFF; } return (int)len; } static void clio_sink_init_fd(struct clio_sink *sink, int fd) { sink->mode = CLIO_SINK_FD; sink->fd = fd; sink->buffer = (char *)0; sink->capacity = 0UL; sink->count = 0UL; sink->failed = 0; } static void clio_sink_init_buffer(struct clio_sink *sink, char *out, clio_size_t out_size) { sink->mode = CLIO_SINK_BUF; sink->fd = -1; sink->buffer = out; sink->capacity = out_size; sink->count = 0UL; sink->failed = 0; if (out != (char *)0 && out_size > 0UL) { out[0] = '\0'; } } static void clio_sink_finalize_buffer(struct clio_sink *sink) { if (sink->mode != CLIO_SINK_BUF || sink->buffer == (char *)0 || sink->capacity == 0UL) { return; } if (sink->count < sink->capacity) { sink->buffer[sink->count] = '\0'; } else { sink->buffer[sink->capacity - 1UL] = '\0'; } } static int clio_sink_emit(struct clio_sink *sink, const char *text, clio_size_t len) { if (sink == (struct clio_sink *)0 || text == (const char *)0 || len == 0UL) { return 1; } if (sink->mode == CLIO_SINK_FD) { if (clio_write_all_fd(sink->fd, text, len) == EOF) { sink->failed = 1; return 0; } } else { if (sink->buffer != (char *)0 && sink->capacity > 0UL) { clio_size_t i; clio_size_t start = sink->count; clio_size_t writable = 0UL; if (start + 1UL < sink->capacity) { writable = (sink->capacity - 1UL) - start; } if (len < writable) { writable = len; } for (i = 0UL; i < writable; i++) { sink->buffer[start + i] = text[i]; } } } sink->count += len; return 1; } static clio_size_t clio_u64_to_base(unsigned long long value, unsigned int base, int uppercase, char *out, clio_size_t out_size) { char tmp[64]; clio_size_t pos = 0UL; clio_size_t i = 0UL; if (out == (char *)0 || out_size < 2UL || base < 2U || base > 16U) { return 0UL; } if (value == 0ULL) { out[0] = '0'; out[1] = '\0'; return 1UL; } while (value != 0ULL && pos < (clio_size_t)sizeof(tmp)) { unsigned long long digit = value % (unsigned long long)base; if (digit < 10ULL) { tmp[pos++] = (char)('0' + digit); } else { char alpha = (uppercase != 0) ? 'A' : 'a'; tmp[pos++] = (char)(alpha + (char)(digit - 10ULL)); } value /= (unsigned long long)base; } if (pos + 1UL > out_size) { return 0UL; } while (pos > 0UL) { pos--; out[i++] = tmp[pos]; } out[i] = '\0'; return i; } static clio_size_t clio_i64_to_dec(long long value, char *out, clio_size_t out_size) { unsigned long long magnitude; clio_size_t offset = 0UL; clio_size_t len; if (out == (char *)0 || out_size < 2UL) { return 0UL; } if (value < 0LL) { out[offset++] = '-'; if (offset + 2UL > out_size) { return 0UL; } magnitude = (unsigned long long)(-(value + 1LL)) + 1ULL; } else { magnitude = (unsigned long long)value; } len = clio_u64_to_base(magnitude, 10U, 0, out + offset, out_size - offset); if (len == 0UL) { return 0UL; } return offset + len; } static int clio_is_digit(char ch) { return (ch >= '0' && ch <= '9') ? 1 : 0; } static int clio_emit_repeat(struct clio_sink *sink, char ch, clio_size_t count) { while (count > 0UL) { if (clio_sink_emit(sink, &ch, 1UL) == 0) { return 0; } count--; } return 1; } static int clio_emit_with_width(struct clio_sink *sink, const char *text, clio_size_t text_len, int left_align, char pad_char, clio_size_t width) { if (left_align == 0 && width > text_len) { if (clio_emit_repeat(sink, pad_char, width - text_len) == 0) { return 0; } } if (text_len > 0UL && clio_sink_emit(sink, text, text_len) == 0) { return 0; } if (left_align != 0 && width > text_len) { if (clio_emit_repeat(sink, ' ', width - text_len) == 0) { return 0; } } return 1; } static int clio_vformat(struct clio_sink *sink, const char *fmt, va_list args) { const char *cursor = fmt; if (sink == (struct clio_sink *)0 || fmt == (const char *)0) { return EOF; } while (*cursor != '\0') { if (*cursor != '%') { if (clio_sink_emit(sink, cursor, 1UL) == 0) { return EOF; } cursor++; continue; } cursor++; if (*cursor == '%') { if (clio_sink_emit(sink, "%", 1UL) == 0) { return EOF; } cursor++; continue; } { int left_align = 0; int zero_pad = 0; clio_size_t width = 0UL; int has_precision = 0; clio_size_t precision = 0UL; int length_mode = 0; /* 0: default, 1: l, 2: ll, 3: z */ char spec = *cursor; char number_buf[96]; while (spec == '-' || spec == '0') { if (spec == '-') { left_align = 1; } else if (spec == '0') { zero_pad = 1; } cursor++; spec = *cursor; } while (clio_is_digit(spec) != 0) { width = (width * 10UL) + (clio_size_t)(unsigned long)(spec - '0'); cursor++; spec = *cursor; } if (spec == '.') { has_precision = 1; precision = 0UL; cursor++; spec = *cursor; while (clio_is_digit(spec) != 0) { precision = (precision * 10UL) + (clio_size_t)(unsigned long)(spec - '0'); cursor++; spec = *cursor; } } if (spec == 'l') { cursor++; spec = *cursor; length_mode = 1; if (spec == 'l') { cursor++; spec = *cursor; length_mode = 2; } } else if (spec == 'z') { cursor++; spec = *cursor; length_mode = 3; } if (spec == '\0') { break; } if (spec == 's') { const char *text = va_arg(args, const char *); clio_size_t text_len; if (text == (const char *)0) { text = "(null)"; } text_len = clio_strlen(text); if (has_precision != 0 && precision < text_len) { text_len = precision; } if (clio_emit_with_width(sink, text, text_len, left_align, ' ', width) == 0) { return EOF; } } else if (spec == 'c') { char out = (char)va_arg(args, int); char out_buf[1]; out_buf[0] = out; if (clio_emit_with_width(sink, out_buf, 1UL, left_align, ' ', width) == 0) { return EOF; } } else if (spec == 'd' || spec == 'i') { long long value; char sign_char = '\0'; const char *digits = number_buf; clio_size_t digits_len; clio_size_t leading_zeros = 0UL; clio_size_t core_len; int sign_emitted = 0; if (length_mode == 2) { value = va_arg(args, long long); } else if (length_mode == 1) { value = (long long)va_arg(args, long); } else if (length_mode == 3) { value = (long long)va_arg(args, long long); } else { value = (long long)va_arg(args, int); } digits_len = clio_i64_to_dec(value, number_buf, (clio_size_t)sizeof(number_buf)); if (digits_len == 0UL) { return EOF; } if (number_buf[0] == '-') { sign_char = '-'; digits = number_buf + 1; digits_len--; } if (has_precision != 0 && precision == 0UL && value == 0LL) { digits_len = 0UL; } if (has_precision != 0 && precision > digits_len) { leading_zeros = precision - digits_len; } core_len = digits_len + leading_zeros + ((sign_char != '\0') ? 1UL : 0UL); if (left_align == 0 && width > core_len) { if (zero_pad != 0 && has_precision == 0) { if (sign_char != '\0') { if (clio_sink_emit(sink, &sign_char, 1UL) == 0) { return EOF; } sign_emitted = 1; } if (clio_emit_repeat(sink, '0', width - core_len) == 0) { return EOF; } } else { if (clio_emit_repeat(sink, ' ', width - core_len) == 0) { return EOF; } } } if (sign_char != '\0' && sign_emitted == 0) { if (clio_sink_emit(sink, &sign_char, 1UL) == 0) { return EOF; } } if (clio_emit_repeat(sink, '0', leading_zeros) == 0) { return EOF; } if (digits_len > 0UL && clio_sink_emit(sink, digits, digits_len) == 0) { return EOF; } if (left_align != 0 && width > core_len) { if (clio_emit_repeat(sink, ' ', width - core_len) == 0) { return EOF; } } } else if (spec == 'u' || spec == 'x' || spec == 'X') { unsigned long long value; unsigned int base = (spec == 'u') ? 10U : 16U; int upper = (spec == 'X') ? 1 : 0; clio_size_t digits_len; clio_size_t leading_zeros = 0UL; clio_size_t core_len; char pad_char = ' '; if (length_mode == 2) { value = va_arg(args, unsigned long long); } else if (length_mode == 1) { value = (unsigned long long)va_arg(args, unsigned long); } else if (length_mode == 3) { value = (unsigned long long)va_arg(args, unsigned long long); } else { value = (unsigned long long)va_arg(args, unsigned int); } digits_len = clio_u64_to_base(value, base, upper, number_buf, (clio_size_t)sizeof(number_buf)); if (digits_len == 0UL) { return EOF; } if (has_precision != 0 && precision == 0UL && value == 0ULL) { digits_len = 0UL; } if (has_precision != 0 && precision > digits_len) { leading_zeros = precision - digits_len; } core_len = digits_len + leading_zeros; if (zero_pad != 0 && has_precision == 0 && left_align == 0) { pad_char = '0'; } if (left_align == 0 && width > core_len) { if (clio_emit_repeat(sink, pad_char, width - core_len) == 0) { return EOF; } } if (clio_emit_repeat(sink, '0', leading_zeros) == 0) { return EOF; } if (digits_len > 0UL && clio_sink_emit(sink, number_buf, digits_len) == 0) { return EOF; } if (left_align != 0 && width > core_len) { if (clio_emit_repeat(sink, ' ', width - core_len) == 0) { return EOF; } } } else if (spec == 'p') { const void *ptr = va_arg(args, const void *); unsigned long long value = (unsigned long long)(usize)ptr; clio_size_t digits_len; clio_size_t leading_zeros = 0UL; clio_size_t core_len; digits_len = clio_u64_to_base(value, 16U, 0, number_buf, (clio_size_t)sizeof(number_buf)); if (digits_len == 0UL) { return EOF; } if (has_precision != 0 && precision == 0UL && value == 0ULL) { digits_len = 0UL; } if (has_precision != 0 && precision > digits_len) { leading_zeros = precision - digits_len; } core_len = 2UL + leading_zeros + digits_len; if (left_align == 0 && width > core_len) { if (clio_emit_repeat(sink, ' ', width - core_len) == 0) { return EOF; } } if (clio_sink_emit(sink, "0x", 2UL) == 0) { return EOF; } if (clio_emit_repeat(sink, '0', leading_zeros) == 0) { return EOF; } if (digits_len > 0UL && clio_sink_emit(sink, number_buf, digits_len) == 0) { return EOF; } if (left_align != 0 && width > core_len) { if (clio_emit_repeat(sink, ' ', width - core_len) == 0) { return EOF; } } } else if (spec == 'n') { int *out_count = va_arg(args, int *); if (out_count != (int *)0) { if (sink->count > 0x7FFFFFFFUL) { *out_count = 0x7FFFFFFF; } else { *out_count = (int)sink->count; } } } else { char fallback[2]; fallback[0] = spec; fallback[1] = '\0'; if (clio_sink_emit(sink, "%", 1UL) == 0 || clio_sink_emit(sink, fallback, 1UL) == 0) { return EOF; } } cursor++; } } if (sink->mode == CLIO_SINK_BUF) { clio_sink_finalize_buffer(sink); } if (sink->failed != 0) { return EOF; } if (sink->count > 0x7FFFFFFFUL) { return 0x7FFFFFFF; } return (int)sink->count; } int putchar(int ch) { char out = (char)(ch & 0xFF); return (clio_write_all_fd(1, &out, 1UL) == EOF) ? EOF : (int)(unsigned char)out; } int getchar(void) { char ch = '\0'; for (;;) { u64 got = cleonos_sys_fd_read(0ULL, &ch, 1ULL); if (got == 1ULL) { return (int)(unsigned char)ch; } if (got == (u64)-1) { return EOF; } (void)cleonos_sys_yield(); } } int fputc(int ch, int fd) { char out = (char)(ch & 0xFF); return (clio_write_all_fd(fd, &out, 1UL) == EOF) ? EOF : (int)(unsigned char)out; } int fgetc(int fd) { char ch = '\0'; if (fd < 0) { return EOF; } for (;;) { u64 got = cleonos_sys_fd_read((u64)fd, &ch, 1ULL); if (got == 1ULL) { return (int)(unsigned char)ch; } if (got == (u64)-1) { return EOF; } (void)cleonos_sys_yield(); } } int fputs(const char *text, int fd) { clio_size_t len; if (text == (const char *)0) { return EOF; } len = clio_strlen(text); return clio_write_all_fd(fd, text, len); } int puts(const char *text) { int wrote = fputs(text, 1); if (wrote == EOF) { return EOF; } if (putchar('\n') == EOF) { return EOF; } return wrote + 1; } int vsnprintf(char *out, unsigned long out_size, const char *fmt, va_list args) { struct clio_sink sink; va_list args_copy; int rc; clio_sink_init_buffer(&sink, out, out_size); va_copy(args_copy, args); rc = clio_vformat(&sink, fmt, args_copy); va_end(args_copy); return rc; } int snprintf(char *out, unsigned long out_size, const char *fmt, ...) { va_list args; int rc; va_start(args, fmt); rc = vsnprintf(out, out_size, fmt, args); va_end(args); return rc; } int vdprintf(int fd, const char *fmt, va_list args) { struct clio_sink sink; va_list args_copy; int rc; clio_sink_init_fd(&sink, fd); va_copy(args_copy, args); rc = clio_vformat(&sink, fmt, args_copy); va_end(args_copy); return rc; } int dprintf(int fd, const char *fmt, ...) { va_list args; int rc; va_start(args, fmt); rc = vdprintf(fd, fmt, args); va_end(args); return rc; } int vfprintf(int fd, const char *fmt, va_list args) { return vdprintf(fd, fmt, args); } int fprintf(int fd, const char *fmt, ...) { va_list args; int rc; va_start(args, fmt); rc = vdprintf(fd, fmt, args); va_end(args); return rc; } int vprintf(const char *fmt, va_list args) { return vdprintf(1, fmt, args); } int printf(const char *fmt, ...) { va_list args; int rc; va_start(args, fmt); rc = vdprintf(1, fmt, args); va_end(args); return rc; }