diff --git a/apps/src/init.c b/apps/src/init.c index 0f6ea89f..8f23a859 100644 --- a/apps/src/init.c +++ b/apps/src/init.c @@ -1,16 +1,10 @@ #include +#include #include #include #include #include -static void print(const char* message) -{ - syscall(SYS_write, message, strlen(message)); -} - -#define println(message) print(message "\n") - int main() { if (gettid() == 0) // why are we the idle task? @@ -18,29 +12,27 @@ int main() __luna_abort("SHENANIGANS! init is tid 0 (which is reserved for the idle task)\n"); } - println("Welcome to Luna from a C init!"); - println(""); + printf("Welcome to Luna!\n"); + + printf("Running as tid %ld\n\n", gettid()); sleep(1); - print("Your kernel version is "); - char version[40]; syscall(SYS_getversion, version, sizeof(version)); - print(version); - println("\n"); + printf("Your kernel version is %s\n\n", version); sleep(2); { - [[maybe_unused]] volatile int i; char* variable = malloc(200); *variable = 3; + printf("Allocated variable at address %lx\n", (unsigned long int)variable); free(variable); } - println("Press any key to restart."); + printf("Press any key to restart.\n"); return 0; } diff --git a/libs/libc/include/stdio.h b/libs/libc/include/stdio.h index 6baf5713..2197ae13 100644 --- a/libs/libc/include/stdio.h +++ b/libs/libc/include/stdio.h @@ -28,6 +28,8 @@ extern "C" size_t fwrite(const void*, size_t, size_t, FILE*); void setbuf(FILE*, char*); int vfprintf(FILE*, const char*, va_list); + int printf(const char*, ...); + int puts(const char*); #ifdef __cplusplus } diff --git a/libs/libc/src/printf.cpp b/libs/libc/src/printf.cpp new file mode 100644 index 00000000..e65f3ac7 --- /dev/null +++ b/libs/libc/src/printf.cpp @@ -0,0 +1,259 @@ +#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 printf(const char* format, ...) + { + va_list ap; + va_start(ap, format); + int written = internal_printf( + format, [](const char* s) { syscall(SYS_write, s, strlen(s)); }, -1, ap); + va_end(ap); + return written; + } +} \ No newline at end of file diff --git a/libs/libc/src/stdio.cpp b/libs/libc/src/stdio.cpp index ca3b4d71..d7817778 100644 --- a/libs/libc/src/stdio.cpp +++ b/libs/libc/src/stdio.cpp @@ -1,5 +1,9 @@ #include #include +#include +#include +#include +#include extern "C" { @@ -43,4 +47,12 @@ extern "C" { NOT_IMPLEMENTED("vfprintf"); } + int puts(const char* s) + { + size_t len = strlen(s); + char* output = (char*)__builtin_alloca(len + 1); + memcpy(output, s, len); + output[len] = '\n'; + return syscall(SYS_write, output, len + 1); + } } \ No newline at end of file