161 lines
3.4 KiB
C
161 lines
3.4 KiB
C
#include "../include/stdio.h"
|
|
#include <stdbool.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include "../include/string.h"
|
|
|
|
#ifdef __is_katauos
|
|
#include "../include/screen.h"
|
|
#endif
|
|
|
|
int puts(const char* string) {
|
|
return printf("%s\n", string);
|
|
}
|
|
|
|
int putchar(int ic) {
|
|
#if defined(__is_katauos)
|
|
char c = (char) ic;
|
|
terminal_write(&c, sizeof(c));
|
|
#else
|
|
// TODO: Implement stdio and the write system call.
|
|
#endif
|
|
return ic;
|
|
}
|
|
|
|
void intToString(int value, char *buffer, char format) {
|
|
int i = 0;
|
|
int isNegative = 0;
|
|
unsigned int uValue;
|
|
|
|
if (format == 'd') {
|
|
if (value < 0) {
|
|
isNegative = 1;
|
|
uValue = -value;
|
|
} else {
|
|
uValue = value;
|
|
}
|
|
|
|
do {
|
|
buffer[i++] = '0' + (uValue % 10);
|
|
uValue /= 10;
|
|
} while (uValue > 0);
|
|
|
|
if (isNegative) {
|
|
buffer[i++] = '-';
|
|
}
|
|
} else if (format == 'x' || format == 'X') {
|
|
uValue = (unsigned int)value;
|
|
|
|
do {
|
|
int digit = uValue % 16;
|
|
if (digit < 10) {
|
|
buffer[i++] = '0' + digit;
|
|
} else {
|
|
buffer[i++] = (format == 'x') ? ('a' + digit - 10) : ('A' + digit - 10);
|
|
}
|
|
uValue /= 16;
|
|
} while (uValue > 0);
|
|
} else {
|
|
buffer[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
for (int j = 0; j < i / 2; j++) {
|
|
char temp = buffer[j];
|
|
buffer[j] = buffer[i - j - 1];
|
|
buffer[i - j - 1] = temp;
|
|
}
|
|
|
|
buffer[i] = '\0';
|
|
}
|
|
|
|
static bool print(const char* data, size_t length) {
|
|
const unsigned char* bytes = (const unsigned char*) data;
|
|
for (size_t i = 0; i < length; i++)
|
|
if (putchar(bytes[i]) == EOF)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
int printf(const char* restrict format, ...) {
|
|
va_list parameters;
|
|
va_start(parameters, format);
|
|
|
|
int written = 0;
|
|
|
|
while (*format != '\0') {
|
|
size_t maxrem = INT_MAX - written;
|
|
|
|
if (format[0] != '%' || format[1] == '%') {
|
|
if (format[0] == '%')
|
|
format++;
|
|
size_t amount = 1;
|
|
while (format[amount] && format[amount] != '%')
|
|
amount++;
|
|
if (maxrem < amount) {
|
|
// TODO: Set errno to EOVERFLOW.
|
|
return -1;
|
|
}
|
|
if (!print(format, amount))
|
|
return -1;
|
|
format += amount;
|
|
written += amount;
|
|
continue;
|
|
}
|
|
|
|
const char* format_begun_at = format++;
|
|
|
|
if (*format == 'c') {
|
|
format++;
|
|
char c = (char) va_arg(parameters, int /* char promotes to int */);
|
|
if (!maxrem) {
|
|
// TODO: Set errno to EOVERFLOW.
|
|
return -1;
|
|
}
|
|
if (!print(&c, sizeof(c)))
|
|
return -1;
|
|
written++;
|
|
} else if (*format == 's') {
|
|
format++;
|
|
const char* str = va_arg(parameters, const char*);
|
|
size_t len = strlen(str);
|
|
if (maxrem < len) {
|
|
// TODO: Set errno to EOVERFLOW.
|
|
return -1;
|
|
}
|
|
if (!print(str, len))
|
|
return -1;
|
|
written += len;
|
|
} else if(*format == 'x' || *format == 'X') {
|
|
format++;
|
|
int number = va_arg(parameters, int);
|
|
char str[256];
|
|
|
|
if(*format == 'x')
|
|
intToString(number, str, 'x');
|
|
else
|
|
intToString(number, str, 'X');
|
|
|
|
size_t len = strlen(str);
|
|
if(!print(str, len))
|
|
return -1;
|
|
written += strlen(str);
|
|
|
|
} else {
|
|
format = format_begun_at;
|
|
size_t len = strlen(format);
|
|
if (maxrem < len) {
|
|
// TODO: Set errno to EOVERFLOW.
|
|
return -1;
|
|
}
|
|
if (!print(format, len))
|
|
return -1;
|
|
written += len;
|
|
format += len;
|
|
}
|
|
}
|
|
|
|
va_end(parameters);
|
|
return written;
|
|
}
|