#include #include #include #include #include #include #include #include typedef long int ssize_t; static void __strrev(char* arr, int size) { int left = 0; int right = size - 1; for (int i = left; i < right; i++) { char temp = arr[i]; arr[i] = arr[right]; arr[right] = temp; right--; } } template static char* __unsignedtoa(IntegerType number, char* arr, int base) { int i = 0; IntegerType r = 0; if (number == 0) { arr[i] = '0'; arr[i + 1] = '\0'; return arr; } while (number != 0) { r = number % base; arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0'; i++; number /= base; } __strrev(arr, i - 1); arr[i] = '\0'; return arr; } template static char* __signedtoa(IntegerType number, char* arr, int base) { if (number < 0 && base == 10) { return __unsignedtoa((UnsignedIntegerType)(-number), arr, base); } return __unsignedtoa((UnsignedIntegerType)number, arr, base); } template static int internal_printf(const char* format, PutString put_string_callback, ssize_t max, va_list ap) { char buffer[1025]; // 1024 with null terminator size_t format_size = strlen(format); size_t format_index = 0; size_t buffer_insert_index = 0; ssize_t max_remaining = max; size_t written = 0; auto flush_buffer = [&]() { size_t buffer_length = buffer_insert_index; written += buffer_length; buffer_insert_index = 0; if (max_remaining < 0) { buffer[buffer_length] = 0; put_string_callback(buffer); return; } if (max_remaining == 0) { return; } if (buffer_length <= (size_t)max_remaining) { max_remaining -= buffer_length; buffer[buffer_length] = 0; put_string_callback(buffer); } else { buffer[max_remaining] = 0; max_remaining = 0; put_string_callback(buffer); } }; bool is_long = false; bool is_unsigned_long = false; bool preserve_format = false; while (format_index < format_size) { char current_char = format[format_index]; if (current_char == '%' || preserve_format) { if (!preserve_format && format_index + 1 == format_size) // end of format string { format_index++; continue; } else { if (!preserve_format) format_index++; preserve_format = false; current_char = format[format_index]; switch (current_char) { case 'c': { buffer[buffer_insert_index++] = va_arg(ap, int); if (buffer_insert_index == 1024) flush_buffer(); break; } case '%': { buffer[buffer_insert_index++] = '%'; if (buffer_insert_index == 1024) flush_buffer(); break; } case 'z': { is_unsigned_long = true; preserve_format = true; break; } case 'l': { is_long = true; preserve_format = true; break; } case 'd': { if (is_unsigned_long) { char result[25]; __unsignedtoa(va_arg(ap, uint64_t), result, 10); if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, result, strlen(result)); buffer_insert_index += strlen(result); if (buffer_insert_index == 1024) flush_buffer(); is_unsigned_long = is_long = false; } else if (is_long) { char result[25]; __signedtoa(va_arg(ap, int64_t), result, 10); if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, result, strlen(result)); buffer_insert_index += strlen(result); if (buffer_insert_index == 1024) flush_buffer(); is_unsigned_long = is_long = false; } else { char result[25]; __signedtoa(va_arg(ap, int32_t), result, 10); if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, result, strlen(result)); buffer_insert_index += strlen(result); if (buffer_insert_index == 1024) flush_buffer(); } break; } case 'u': { if (is_unsigned_long || is_long) { char result[25]; __unsignedtoa(va_arg(ap, uint64_t), result, 10); if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, result, strlen(result)); buffer_insert_index += strlen(result); if (buffer_insert_index == 1024) flush_buffer(); is_unsigned_long = is_long = false; } else { char result[25]; __unsignedtoa(va_arg(ap, uint32_t), result, 10); if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, result, strlen(result)); buffer_insert_index += strlen(result); if (buffer_insert_index == 1024) flush_buffer(); } break; } case 'x': { if (is_unsigned_long || is_long) { char result[25]; __unsignedtoa(va_arg(ap, uint64_t), result, 16); if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, result, strlen(result)); buffer_insert_index += strlen(result); if (buffer_insert_index == 1024) flush_buffer(); is_unsigned_long = is_long = false; } else { char result[25]; __unsignedtoa(va_arg(ap, uint32_t), result, 16); if (buffer_insert_index + strlen(result) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, result, strlen(result)); buffer_insert_index += strlen(result); if (buffer_insert_index == 1024) flush_buffer(); } break; } case 's': { const char* str = va_arg(ap, const char*); while (strlen(str) > 1024) { flush_buffer(); memcpy(buffer, str, 1024); str += 1024; buffer_insert_index = 1024; } if (buffer_insert_index + strlen(str) > 1024) flush_buffer(); memcpy(buffer + buffer_insert_index, str, strlen(str)); buffer_insert_index += strlen(str); if (buffer_insert_index == 1024) flush_buffer(); break; } default: { NOT_IMPLEMENTED("internal_printf: unknown format specifier"); } } } } else { buffer[buffer_insert_index++] = current_char; if (buffer_insert_index == 1024) flush_buffer(); } format_index++; } if (buffer_insert_index > 0) flush_buffer(); return written; } extern "C" { int vprintf(const char* format, va_list ap) { return internal_printf( format, [](const char* s) { syscall(SYS_write, s, strlen(s)); }, -1, ap); } int vsprintf(char* str, const char* format, va_list ap) { return internal_printf( format, [&](const char* s) { if (str) strcat(str, s); }, -1, ap); } int vsnprintf(char* str, size_t max, const char* format, va_list ap) { return internal_printf( format, [&](const char* s) { if (str) strcat(str, s); }, max == 0 ? 0 : max - 1, ap); } }