separating: there will be libk and libc

This commit is contained in:
2025-01-07 15:23:14 +01:00
parent b3687d20ee
commit a8582ba343
32 changed files with 29 additions and 31 deletions

17
libk/ctype.c Normal file
View File

@@ -0,0 +1,17 @@
// Ctype implementation for blankos/libk
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include <stdint.h>
#include <stdbool.h>
bool isdigit(char c)
{
return c >= '0' && c <= '9';
}
bool isspace(char c)
{
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
}

14
libk/ctype.h Normal file
View File

@@ -0,0 +1,14 @@
// Ctype implementation for blankos/libk header
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#ifndef CTYPE_H
#define CTYPE_H
#include <stdbool.h>
bool isdigit(char c);
bool isspace(char c);
#endif

757
libk/stdio.c Normal file
View File

@@ -0,0 +1,757 @@
// Standard input/output implementation for blankos/libk
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include "../kernel/io.h"
#include "stdio.h"
#include "string.h"
#include <stdint.h>
#include "../kernel/system.h"
#include "../drivers/framebuffer.h"
#include "../drivers/serial.h"
extern uint32_t* framebuffer;
extern uint32_t VGA_WIDTH;
extern uint32_t VGA_HEIGHT;
unsigned int VGA_X = 0, VGA_Y = 0;
extern int scanline;
int get_cursor_x()
{
return VGA_X;
}
int get_cursor_y()
{
return VGA_Y;
}
void draw_cursor(uint32_t color)
{
for (int y=12; y<CURSOR_HEIGHT; y++)
{
for (int x=0; x<CURSOR_WIDTH; x++)
{
putpixel(framebuffer, scanline, 32, VGA_X * CURSOR_WIDTH + x, VGA_Y * CURSOR_HEIGHT + y, color);
}
}
}
void draw_pixel(int x, int y, uint32_t color) //high level wrapper for putpixel
{
putpixel(framebuffer, scanline, 32, x, y, color);
}
void draw_square(int x, int y, uint32_t color, int size)
{
int startx = x*size;
int starty = y*size;
for (int i=0; i<size; i++)
{
for (int j=0; j<size; j++)
{
draw_pixel(startx+i, starty+j, color);
}
}
}
void erase_cursor()
{
draw_cursor(black);
}
void move_cursor(int x, int y)
{
erase_cursor();
VGA_X = x;
VGA_Y = y;
draw_cursor(white);
}
// stdio wrapper for draw_char in graphics mode
void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg)
{
draw_char(c, x, y, fg, bg);
}
void clear(void)
{
for (unsigned int y=0; y<VGA_HEIGHT; y++)
{
for (unsigned int x=0; x<VGA_WIDTH; x++)
{
putchar(' ', x, y, black, black);
}
}
move_cursor(0, 0);
}
void putc(char c)
{
erase_cursor();
switch(c)
{
case '\n':
VGA_X = 0;
VGA_Y++;
break;
case '\r':
VGA_X = 0;
break;
case '\t':
VGA_X += 4;
if (VGA_X >= VGA_WIDTH) {
VGA_X -= VGA_WIDTH;
VGA_Y++;
}
break;
case '\b':
if (VGA_X > 0)
{
VGA_X--;
}
else if (VGA_Y > 0) {
VGA_Y--;
VGA_X = VGA_WIDTH-1;
}
putchar(' ', VGA_X, VGA_Y, white, black);
break;
default:
putchar(c, VGA_X, VGA_Y, white, black);
VGA_X++;
break;
}
if (VGA_X >= VGA_WIDTH)
{
VGA_Y++;
VGA_X = 0;
}
if (VGA_Y >= VGA_HEIGHT)
{
serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT);
scroll();
VGA_Y = VGA_HEIGHT - 1;
}
move_cursor(VGA_X, VGA_Y);
}
void colorputc(char c, uint32_t fg, uint32_t bg)
{
erase_cursor();
switch(c)
{
case '\n':
VGA_X = 0;
VGA_Y++;
break;
case '\r':
VGA_X = 0;
break;
case '\t':
VGA_X += 4;
break;
default:
putchar(c, VGA_X, VGA_Y, fg, bg);
VGA_X++;
break;
}
if (VGA_X >= VGA_WIDTH)
{
VGA_Y++;
VGA_X = 0;
}
if (VGA_Y >= VGA_HEIGHT)
{
serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT);
scroll();
VGA_Y = VGA_HEIGHT - 1;
}
move_cursor(VGA_X, VGA_Y);
}
void puts(const char* str)
{
while (*str)
{
putc(*str);
str++;
}
}
void colorputs(const char* str, uint32_t fg, uint32_t bg)
{
while (*str)
{
colorputc(*str, fg, bg);
str++;
}
}
// double to string for printf
void dtostrf(double val, char *buffer, int precision)
{
int whole_part = (int)val;
double fractional_part = val - whole_part;
if (fractional_part < 0) fractional_part = -fractional_part;
if (whole_part == 0)
{
*buffer++ = '0';
}
else
{
if (whole_part < 0)
{
*buffer++ = '-';
whole_part = -whole_part;
}
char temp[32];
int pos = 0;
while (whole_part > 0)
{
temp[pos++] = '0' + (whole_part % 10);
whole_part /= 10;
}
while (pos > 0)
{
*buffer++ = temp[--pos];
}
}
*buffer++ = '.';
for (int i = 0; i < precision; i++)
{
fractional_part *= 10;
int digit = (int)fractional_part;
*buffer++ = '0' + digit;
fractional_part -= digit;
}
*buffer = '\0';
}
void printf(const char* fmt, ...)
{
int* argp = (int*)&fmt;
int state = PRINTF_STATE_START;
int length = PRINTF_LENGTH_START;
int radix = 10;
bool sign = false;
int width = 0;
char pad_char = ' ';
argp++;
while (*fmt)
{
switch (state)
{
case PRINTF_STATE_START:
if (*fmt == '%')
{
state = PRINTF_STATE_LENGTH;
width = 0;
pad_char = ' ';
}
else
{
putc(*fmt);
}
break;
case PRINTF_STATE_LENGTH:
if (*fmt == '0')
{
pad_char = '0';
state = PRINTF_STATE_WIDTH;
}
else if (*fmt >= '1' && *fmt <= '9')
{
width = *fmt - '0';
state = PRINTF_STATE_WIDTH;
}
else if (*fmt == 'h')
{
length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_SHORT;
}
else if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LONG;
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_WIDTH:
if (*fmt >= '0' && *fmt <= '9')
{
width = width * 10 + (*fmt - '0');
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_SHORT:
if (*fmt == 'h')
{
length = PRINTF_LENGTH_SHORT_SHORT;
state = PRINTF_STATE_SPEC;
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_LONG:
if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC;
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_:
switch (*fmt)
{
case 'c':
putc((char)*argp);
argp++;
break;
case 's':
puts(*(const char**)argp);
argp++;
break;
case '%':
putc('%');
break;
case 'd':
case 'i':
radix = 10;
sign = true;
argp = printf_number(argp, length, sign, radix, width, pad_char);
break;
case 'u':
radix = 10;
sign = false;
argp = printf_number(argp, length, sign, radix, width, pad_char);
break;
case 'X':
case 'x':
case 'p':
radix = 16;
sign = false;
argp = printf_number(argp, length, sign, radix, width, pad_char);
break;
case 'o':
radix = 8;
sign = false;
argp = printf_number(argp, length, sign, radix, width, pad_char);
break;
case 'f': {
double* dargp = (double*)argp;
double d = *(double*)dargp;
char buffer[64];
dtostrf(d, buffer, 6);
puts(buffer);
argp += 2;
break;
}
default:
break;
}
state = PRINTF_STATE_START;
length = PRINTF_LENGTH_START;
radix = 10;
sign = false;
width = 0;
pad_char = ' ';
break;
}
fmt++;
}
}
const char charset[] = "0123456789abcdef";
int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char)
{
char buffer[32];
unsigned long long number;
int number_sign = 1;
int pos = 0;
switch (length)
{
case PRINTF_LENGTH_SHORT_SHORT:
case PRINTF_LENGTH_SHORT:
case PRINTF_LENGTH_START:
if (sign)
{
int n = *argp;
if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
}
else
{
number = *(unsigned int*)argp;
}
argp++;
break;
case PRINTF_LENGTH_LONG:
if (sign)
{
long int n = *(long int*)argp;
if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
}
else
{
number = *(unsigned long int*)argp;
}
argp += 2;
break;
case PRINTF_LENGTH_LONG_LONG:
if (sign)
{
long long int n = *(long long int*)argp;
if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
}
else
{
number = *(unsigned long long int*)argp;
}
argp += 4;
break;
}
do
{
uint32_t rem;
x86_div64_32(number, radix, &number, &rem);
buffer[pos++] = charset[rem];
} while (number > 0);
if (sign && number_sign < 0)
{
buffer[pos++] = '-';
}
int padding = width - pos;
while (padding-- > 0)
{
putc(pad_char);
}
while (--pos >= 0)
{
putc(buffer[pos]);
}
return argp;
}
/*
int getch()
{
return keyboard_getchar();
}
void get_input(char *buffer, int size) {
int index = 0;
char c;
while (index < size-1)
{
c = getch();
if (c == '\n') {
break;
} else if (c == '\b') {
if (index > 0) {
index--;
putc('\b');
putc(' ');
putc('\b');
}
} else {
buffer[index++] = c;
putc(c);
}
}
buffer[index] = '\0';
}
*/
void colorprintf(uint32_t fg, uint32_t bg, const char* fmt, ...)
{
int* argp = (int*)&fmt;
int state = PRINTF_STATE_START;
int length = PRINTF_LENGTH_START;
int radix = 10;
bool sign = false;
int width = 0;
char pad_char = ' ';
argp++;
while (*fmt)
{
switch (state)
{
case PRINTF_STATE_START:
if (*fmt == '%')
{
state = PRINTF_STATE_LENGTH;
width = 0;
pad_char = ' ';
}
else
{
colorputc(*fmt, fg, bg);
}
break;
case PRINTF_STATE_LENGTH:
if (*fmt == '0')
{
pad_char = '0';
state = PRINTF_STATE_WIDTH;
}
else if (*fmt >= '1' && *fmt <= '9')
{
width = *fmt - '0';
state = PRINTF_STATE_WIDTH;
}
else if (*fmt == 'h')
{
length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_SHORT;
}
else if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LONG;
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_WIDTH:
if (*fmt >= '0' && *fmt <= '9')
{
width = width * 10 + (*fmt - '0');
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_SHORT:
if (*fmt == 'h')
{
length = PRINTF_LENGTH_SHORT_SHORT;
state = PRINTF_STATE_SPEC;
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_LONG:
if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC;
}
else
{
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_:
switch (*fmt)
{
case 'c':
colorputc((char)*argp, fg, bg);
argp++;
break;
case 's':
colorputs(*(const char**)argp, fg, bg);
argp++;
break;
case '%':
putc('%');
break;
case 'd':
case 'i':
radix = 10;
sign = true;
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
break;
case 'u':
radix = 10;
sign = false;
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
break;
case 'X':
case 'x':
case 'p':
radix = 16;
sign = false;
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
break;
case 'o':
radix = 8;
sign = false;
argp = colorprintf_number(argp, length, sign, radix, width, pad_char, fg, bg);
break;
case 'f': {
double* dargp = (double*)argp;
double d = *(double*)dargp;
char buffer[64];
dtostrf(d, buffer, 6);
colorputs(buffer, fg, bg);
argp += 2;
break;
}
default:
break;
}
state = PRINTF_STATE_START;
length = PRINTF_LENGTH_START;
radix = 10;
sign = false;
width = 0;
pad_char = ' ';
break;
}
fmt++;
}
}
int* colorprintf_number(int* argp, int length, bool sign, int radix, int width, char pad_char, uint32_t fg, uint32_t bg)
{
char buffer[32];
unsigned long long number;
int number_sign = 1;
int pos = 0;
switch (length)
{
case PRINTF_LENGTH_SHORT_SHORT:
case PRINTF_LENGTH_SHORT:
case PRINTF_LENGTH_START:
if (sign)
{
int n = *argp;
if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
}
else
{
number = *(unsigned int*)argp;
}
argp++;
break;
case PRINTF_LENGTH_LONG:
if (sign)
{
long int n = *(long int*)argp;
if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
}
else
{
number = *(unsigned long int*)argp;
}
argp += 2;
break;
case PRINTF_LENGTH_LONG_LONG:
if (sign)
{
long long int n = *(long long int*)argp;
if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
}
else
{
number = *(unsigned long long int*)argp;
}
argp += 4;
break;
}
do
{
uint32_t rem;
x86_div64_32(number, radix, &number, &rem);
buffer[pos++] = charset[rem];
} while (number > 0);
if (sign && number_sign < 0)
{
buffer[pos++] = '-';
}
int padding = width - pos;
while (padding-- > 0)
{
colorputc(pad_char, fg, bg);
}
while (--pos >= 0)
{
colorputc(buffer[pos], fg, bg);
}
return argp;
}

97
libk/stdio.h Normal file
View File

@@ -0,0 +1,97 @@
// Standard input/output implementation for blankos/libk header
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#ifndef STDIO_H
#define STDIO_H
#include <stdint.h>
#include <stdbool.h>
#define FB_GREEN 2
#define FB_DARK_GREY 8
#define FB_CMD_PORT 0x3D4
#define FB_DATA_PORT 0x3D5
#define FB_HIGH_BYTE_CMD 14
#define FB_LOW_BYTE_CMD 15
#define CURSOR_WIDTH 8
#define CURSOR_HEIGHT 16
void draw_cursor(uint32_t color);
void erase_cursor();
void move_cursor(int x, int y);
void draw_pixel(int x, int y, uint32_t color);
void draw_square(int x, int y, uint32_t color, int size);
void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg);
void puts(const char* str);
void clear(void);
void colorputs(const char* str, uint32_t fg, uint32_t bg);
void putcolor(int x, int y, unsigned int color);
char getchar(int x, int y);
unsigned int getcolor(int x, int y);
void putc(char c);
void colorputc(char c, uint32_t fg, uint32_t bg);
void colorprintf(uint32_t fg, uint32_t bg, const char* fmt, ...);
int* colorprintf_number(int* argp, int length, bool sign, int radix, int width, char pad_char, uint32_t fg, uint32_t bg);
#define PRINTF_STATE_START 0
#define PRINTF_STATE_LENGTH 1
#define PRINTF_STATE_SHORT 2
#define PRINTF_STATE_LONG 3
#define PRINTF_STATE_SPEC 4
#define PRINTF_STATE_WIDTH 5
#define PRINTF_LENGTH_START 0
#define PRINTF_LENGTH_SHORT_SHORT 1
#define PRINTF_LENGTH_SHORT 2
#define PRINTF_LENGTH_LONG 3
#define PRINTF_LENGTH_LONG_LONG 4
void printf(const char* fmt, ...);
int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char);
int getch();
void get_input(char *buffer, int size);
void dtostrf(double val, char *buffer, int precision);
enum Colors
{
// AARRGGBB?
white = 0xFFFFFFFF,
black = 0x00000000,
red = 0x00FF0000,
green = 0x0000FF00,
blue = 0x000000FF,
yellow = 0x00FFFF00,
cyan = 0x0000FFFF,
magenta = 0x00FF00FF,
orange = 0x00FFA500,
purple = 0x00800080,
brown = 0x00A52A2A,
gray = 0x00808080,
pink = 0x00FFC0CB,
lime = 0x00BFFF00,
navy = 0x00000080,
teal = 0x00008080,
maroon = 0x00800000,
olive = 0x00808000,
silver = 0x00C0C0C0,
gold = 0x00FFD700,
indigo = 0x004B0082,
violet = 0x00EE82EE,
coral = 0x00FF7F50,
turquoise = 0x0040E0D0,
salmon = 0x00FA8072,
chocolate = 0x00D2691E,
khaki = 0x00F0E68C,
lavender = 0x00E6E6FA,
beige = 0x00F5F5DC
};
int get_cursor_x();
int get_cursor_y();
#endif

134
libk/string.c Normal file
View File

@@ -0,0 +1,134 @@
// String operations implementation for blankos/libk
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#include <stdint.h>
#include "../kernel/system.h"
int strlen(const char* str)
{
int len = 0;
while (*str++)
{
len++;
}
return len;
}
int strcmp(const char* str1, const char* str2)
{
while (*str1 && (*str1 == *str2))
{
str1++;
str2++;
}
return *(const unsigned char*)str1 - *(const unsigned char*)str2;
}
char* strchr(const char* str, int c)
{
while (*str)
{
if (*str == (char)c)
{
return (char*)str;
}
str++;
}
if (c == '\0')
{
return (char*)str;
}
return NULL;
}
char* strtok(char* str, const char* delimiter)
{
static char* last;
if (str)
{
last = str;
} else {
str = last;
}
if (!str || *str == '\0')
{
return NULL;
}
char* token_start = str;
while (*str && !strchr(delimiter, *str))
{
str++;
}
if (*str)
{
*str = '\0';
last = str + 1;
} else {
last = NULL;
}
return token_start;
}
int atoi(char* str)
{
int result = 0;
for (int i=0; str[i] != '\0'; i++)
{
result = result*10 + str[i] - '0';
}
return result;
}
void strcat(char* dest, const char* src)
{
while (*dest)
{
dest++;
}
while (*src)
{
*dest = *src;
dest++;
src++;
}
*dest = '\0';
}
size_t strnlen(const char* str, size_t max_len)
{
size_t len = 0;
while (*str && len < max_len)
{
len++;
str++;
}
return len;
}
void strncat(char* dest, const char* src, size_t n)
{
while (*dest)
{
dest++;
}
while (*src && n > 0)
{
*dest = *src;
dest++;
src++;
n--;
}
*dest = '\0';
}

21
libk/string.h Normal file
View File

@@ -0,0 +1,21 @@
// String operations implementation for blankos/libk header
// Author: xamidev
// Licensed under the Unlicense. See the repo below.
// https://github.com/xamidev/blankos
#ifndef STRING_H
#define STRING_H
#include "../kernel/system.h"
int strlen(const char* str);
int strcmp(const char* str1, const char* str2);
char* strtok(char* str, const char* delimiter);
int atoi(char* str);
void strcat(char* dest, const char* src);
// Safer functions
size_t strnlen(const char* str, size_t max_len);
void strncat(char* dest, const char* src, size_t n);
#endif