Espresso 0.0.1a

This commit is contained in:
2025-06-17 15:50:07 -05:00
parent eeea3b2d86
commit fca025a9bf
24 changed files with 1080 additions and 600 deletions

View File

@ -1,5 +1,3 @@
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <drivers/ide.h> #include <drivers/ide.h>
@ -7,214 +5,89 @@
#include <fs/duckfs.h> #include <fs/duckfs.h>
#define DFS_MAGIC 0xDF1984CC
#define DFS_BLOCK_SIZE 512
#define DFS_VERSION_0 "DuckFS, wheresDax?"
#define DFS_VERSION_1 "DuckFS, Terminator"
#define DFS_VERSION_2 "DuckFS-Terminator2"
#define DFS_VERSION_3 "DuckFS,StarWarsEIV"
#define DFS_VERSION_4 "DuckFS QUACK,QUACK"
#define DFS_FILE_ERROR -8
#define DFS_FILE_UNUSED -1
#define DFS_FILE_USED 0
#define DFS_FILE_TEXT 0
#define DFS_FILE_BINARY 1
#define DFS_FILE_DIRECTORY 2
/* encryption algorithms */
#define DFS_CAESAR_5 88
#define DFS_CAESAR_8 84
#define DFS_CAESAR_2 09
#define DFS_QUACK_32 99
#define DFS_MAX_FILENAME_LEN 64
#define DFS_MAX_FILES 256
typedef struct duckfs_file_header {
char filename[DFS_MAX_FILENAME_LEN + 1]; /* + 1 for the \0 */
char permissions[3]; /* Same thing here */
/*
512 Bytes per sector, meaning a 2 sector file is 1024 bytes, or 1 KiB.
Only valid if this file is not a directory.
*/
int32_t num_sectors;
int16_t type; /* Indicates the file type. -1 for null file, 0 for a text file, 1 for a binary file, and 2 for a directory. */
uint16_t _reserved0; /* (align to 4) */
struct duckfs_file_header* next; /* Next file in the directory this file is in. */
struct duckfs_file_header* contents; /* contains the first file in the directory. only valid if this file is a directory. */
struct duckfs_file_header* parent; /* The directory this file is in. */
uint64_t next_lba; /* The LBA of the next file's file header on the disk. */
uint64_t contents_lba;
uint64_t parent_lba;
uint64_t lba_start; /* only is valid if this file is not a directory. */
uint64_t lba_end; /* only is valid if this file is not a directory. */
uint8_t _reserved1[126]; /* padding to 256 bytes total */
} duckfs_file_header_t;
typedef struct duckfs_superblock {
int32_t duckfs_magic; /* must be DFS_MAGIC. */
char duckfs_version_string[19];
char volume_label[19]; /* 18 characters and a null zero. */
int16_t encryption;
uint64_t duckfs_root; /* LBA of the root directory's file header */
uint32_t _padding[115]; /* padding to 512 bytes total */
} duckfs_superblock_t;
static uint16_t duckfs_initialized = 0; static uint16_t duckfs_initialized = 0;
static duckfs_file_header_t duckfs_root; static duckfs_file_header_t duckfs_root;
const char* duckfs_versions[18] = { DFS_VERSION_0, DFS_VERSION_1, DFS_VERSION_2, DFS_VERSION_3, DFS_VERSION_4 }; const char* duckfs_versions[18] = { DFS_VERSION_0, DFS_VERSION_1, DFS_VERSION_2, DFS_VERSION_3, DFS_VERSION_4 };
int32_t duckfs_init(int16_t drive) void duckfs_init(void)
{ {
char duckfs_header_block[512]; printf("\t%i\n", (sizeof(duckfs_file_header_t)));
if (ide_read48(drive, 0xA, 1, duckfs_header_block) != 0) printf("\t\t%i\n", (sizeof(duckfs_superblock_t)));
{ /* int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) */
printf("[ DEBUG ] Disk read error on drive #%i\n", drive); /* int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) */
return -1;
}
duckfs_superblock_t* superblock = (duckfs_superblock_t*)duckfs_header_block; /*uint8_t superblock_sector[512] = { 0 };
/*
if (superblock->duckfs_magic != (int32_t) DFS_MAGIC)
{
return -2;
}
bool compliant = false;
for (int16_t i = 0; i < 5; ++i)
{
if (strcmp(superblock->duckfs_version_string, duckfs_versions[i]) == 0)
{
compliant = true;
}
}
if (compliant == false)
{
return -3;
}*/
memset(&duckfs_root, 0, sizeof(duckfs_root));
strncpy(duckfs_root.filename, "/", DFS_MAX_FILENAME_LEN);
strncpy(duckfs_root.permissions, "RW", sizeof(duckfs_root.permissions));
duckfs_root.num_sectors = -1;
duckfs_root.type = DFS_FILE_DIRECTORY;
duckfs_root.next = NULL;
duckfs_root.prev = NULL;
duckfs_root.contents = NULL;
duckfs_root.lba_start = 0;
duckfs_root.lba_end = 0;
duckfs_root.contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES);
if (!duckfs_root.contents) {
printf("Memory allocation failed for duckfs_root.contents\n");
return -4;
}
for (int32_t i = 0; i < DFS_MAX_FILES; i++) {
duckfs_root.contents[i].type = DFS_FILE_UNUSED;
}
duckfs_initialized = 1;
return 0;
}
void duckfs_format(int16_t drive)
{
/* Nothing to do, DuckFS does not require formatting. */
}
int32_t duckfs_makedir(const char* filename, const char* perms)
{
duckfs_file_header_t* dir = malloc(sizeof(duckfs_file_header_t));
if (!dir)
{
return -1;
}
if (strlen(perms) < 3)
{
return -2;
}
char p[3] = { "." };
p[0] = perms[0];
p[1] = perms[1];
p[2] = perms[2];
char filen[DFS_MAX_FILENAME_LEN + 1];
char perma[3];
strcpy(filen, filename);
strcpy(perma, perms);
strncpy(dir->filename, filen, sizeof(dir->filename) - 1);
dir->filename[sizeof(dir->filename) - 1] = '\0';
strncpy(dir->permissions, p, sizeof(dir->permissions));
dir->type = DFS_FILE_DIRECTORY;
dir->contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES);
if (!dir->contents) {
free(dir);
return -1;
}
for (int i = 0; i < DFS_MAX_FILES; i++) {
dir->contents[i].type = DFS_FILE_UNUSED;
}
return 0;
}
void duckfs_free_directory(duckfs_file_header_t* dir)
{
if (!dir || dir->type != DFS_FILE_DIRECTORY || !dir->contents)
{
return;
}
for (int i = 0; i < DFS_MAX_FILES; i++) {
duckfs_file_header_t* entry = &dir->contents[i];
if (entry->type == DFS_FILE_UNUSED)
{
continue;
}
if (entry->type == DFS_FILE_DIRECTORY) {
duckfs_free_directory(entry);
}
}
free(dir->contents);
dir->contents = NULL;
}
bool duckfs_add_entry(duckfs_file_header_t* dir, duckfs_file_header_t* entry)
{
if (dir->type != DFS_FILE_DIRECTORY || !dir->contents)
{
return false;
}
for (int i = 0; i < DFS_MAX_FILES; i++) {
if (dir->contents[i].type == DFS_FILE_UNUSED) {
dir->contents[i] = *entry;
return true;
}
}
return false; /* Directory full */
}
duckfs_file_header_t duckfs_create_entry(const char* name, const char* perms, const char* type)
{
duckfs_file_header_t entry = {0};
strncpy(entry.filename, name, DFS_MAX_FILENAME_LEN);
strncpy(entry.permissions, perms, sizeof(entry.permissions) - 1);
int16_t itype = DFS_FILE_UNUSED;
if (strcmp(type, "text") == 0)
{
itype = DFS_FILE_TEXT;
}
else if (strcmp(type, "bin") == 0)
{
itype = DFS_FILE_BINARY;
}
else if (strcmp(type, "dir") == 0)
{
itype = DFS_FILE_BINARY;
}
else
{
duckfs_file_header_t vvvv = { .type = DFS_FILE_ERROR };
return vvvv;
}
entry.num_sectors = 0;
entry.type = itype;
entry.next = NULL;
entry.prev = NULL;
entry.contents = NULL;
entry.lba_start = 0;
entry.lba_end = 0;
if (itype == DFS_FILE_DIRECTORY)
{
entry.contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES);
if (entry.contents)
{
for (int i = 0; i < DFS_MAX_FILES; i++)
{
entry.contents[i].type = DFS_FILE_UNUSED;
}
}
}
return entry;
}
duckfs_file_header_t duckfs_makefile(const char* filename, const char* perms, duckfs_file_header_t parent)
{
ide_read*/
} }

348
drivers/fs/ramfs.c Normal file
View File

@ -0,0 +1,348 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fs/ramfs.h>
static ramfs_file_header_t* ramfs_root = NULL;
static int32_t ramfs_num_files = 0;
static int32_t next_fd = 2;
bool ramfs_initialized = false;
void ramfs_init(void)
{
if (!ramfs_initialized)
{
/*printf("%i\n", (int32_t)sizeof(ramfs_file_header_t));*/
ramfs_initialized = true;
}
}
ramfs_file_header_t* ramfs_make_root(void)
{
ramfs_root = (ramfs_file_header_t*)malloc(sizeof(ramfs_file_header_t));
if (!ramfs_root)
{
printf("RAMFS: Error: malloc failed on attempt to malloc ramfs_root\n");
return NULL;
}
strcpy(ramfs_root->filename, "/");
ramfs_root->type = RAMFS_FILE_DIR;
ramfs_root->encryption = RAMFS_ENCR_NONE;
ramfs_root->content = NULL;
ramfs_root->parent = NULL;
ramfs_root->next = NULL;
ramfs_root->link_target = NULL;
ramfs_root->fd = 0;
return ramfs_root;
}
ramfs_file_header_t* ramfs_get_root(void)
{
if (!ramfs_root)
{
return NULL;
}
return ramfs_root;
}
int32_t ramfs_get_files(void)
{
return ramfs_num_files;
}
bool ramfs_get_initialized(void)
{
return ramfs_initialized;
}
ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent)
{
if (!parent)
{
return NULL;
}
if ((strlen(name) + 1) > RAMFS_FILENAME_LEN)
{
return NULL;
}
ramfs_file_header_t* _file = (ramfs_file_header_t*)malloc(sizeof(ramfs_file_header_t));
if (!_file)
{
printf("RAMFS: Error: malloc failed on attempt to malloc _file (in ramfs_create_file)\n");
return NULL;
}
strcpy(_file->filename, name);
_file->type = type;
_file->encryption = encryption;
_file->content = NULL;
_file->parent = parent;
_file->next = NULL;
_file->link_target = NULL;
_file->fd = (next_fd - 1);
_file->data_begin = (void*)0x0;
_file->data_end = (void*)0x0;
if (parent->content != NULL)
{
ramfs_file_header_t* current = parent->content;
/* Traverse to the end of the linked list */
while (current->next != NULL)
{
current = current->next;
}
/* Append the new file at the end */
current->next = _file;
}
else
{
/* If no content yet, this is the first child */
parent->content = _file;
}
ramfs_num_files++;
next_fd++;
return _file;
}
ramfs_file_header_t* ramfs_write_file(ramfs_file_header_t* file, void* data, size_t len)
{
if (!file || !data || !len || file->type == RAMFS_FILE_DIR)
{
return NULL;
}
/* Free existing data */
if (file->data_begin)
{
free(file->data_begin);
file->data_begin = NULL;
file->data_end = NULL;
}
void* new_buf = malloc(len);
if (!new_buf)
{
return NULL;
}
memcpy(new_buf, data, len);
file->data_begin = new_buf;
file->data_end = (uint8_t*)new_buf + len;
return file;
}
int32_t ramfs_read_file(ramfs_file_header_t* file, void* buffer, size_t buffer_len)
{
if (!file)
{
return -1;
}
if (!buffer)
{
return -2;
}
if (file->type == RAMFS_FILE_DIR)
{
return -3;
}
if (!file->data_begin || !file->data_end)
{
return -4; /* No data to read */
}
size_t data_len = (size_t)((char*)file->data_end - (char*)file->data_begin);
if (buffer_len < data_len)
{
return -5; /* Buffer too small */
}
memcpy(buffer, file->data_begin, data_len);
return (int32_t)data_len; /* return number of bytes copied */
}
int32_t ramfs_delete_file(ramfs_file_header_t* file)
{
if (!file)
{
return -1;
}
if (!file->parent)
{
return -2; /* Don't delete the root or orphaned files */
}
ramfs_file_header_t* parent = file->parent;
ramfs_file_header_t* current = parent->content;
ramfs_file_header_t* prev = NULL;
/* Find the file in the linked list */
while (current && current != file)
{
prev = current;
current = current->next;
}
if (!current)
{
return -3; /* File not found in parent's content list */
}
/* Unlink the file from the list */
if (prev)
{
prev->next = current->next;
}
else
{
parent->content = current->next;
}
/* Recursively delete content if it's a directory */
if (file->type == RAMFS_FILE_DIR && file->content)
{
ramfs_file_header_t* child = file->content;
while (child)
{
ramfs_file_header_t* next_child = child->next;
ramfs_delete_file(child);
child = next_child;
}
}
/* Free file data if applicable */
if ((file->type == RAMFS_FILE_TEXT || file->type == RAMFS_FILE_BINARY) && file->data_begin)
{
free(file->data_begin);
}
/* Free the file header itself */
free(file);
next_fd--;
return 0;
}
ramfs_file_header_t* ramfs_resolve_path(const char* path)
{
if (!path || !ramfs_get_root())
{
return NULL;
}
ramfs_file_header_t* current;
/* Start from root if absolute path */
if (path[0] == '/')
{
current = ramfs_get_root();
path++;
}
else
{
/* TODO: make a ramfs_get_cwd and use it instead */
current = ramfs_get_root();
}
char* path_copy = strdup(path);
if (!path_copy)
{
return NULL;
}
char* token = strtok(path_copy, "/");
while (token && current)
{
if (strcmp(token, ".") == 0)
{
/* Stay in the same directory */
}
else if (strcmp(token, "..") == 0)
{
if (current->parent)
{
current = current->parent;
}
}
else
{
/* Traverse to matching child */
ramfs_file_header_t* child = current->content;
current = NULL;
while (child)
{
if (strcmp(child->filename, token) == 0)
{
current = child;
break;
}
child = child->next;
}
if (!current)
{
/* Not found */
break;
}
}
token = strtok(NULL, "/");
}
free(path_copy);
return current; /* NULL if not found or invalid path */
}
ramfs_file_header_t* ramfs_resolve_fd_dir(ramfs_file_header_t* current, int32_t fd)
{
if (!current)
{
return NULL;
}
if (current->fd == fd)
{
return current;
}
ramfs_file_header_t* found = ramfs_resolve_fd_dir(current->content, fd);
if (found)
{
return found;
}
return ramfs_resolve_fd_dir(current->next, fd);
}
ramfs_file_header_t* ramfs_resolve_fd(int32_t fd)
{
return ramfs_resolve_fd_dir(ramfs_root, fd);
}

230
drivers/fs/vfs.c Normal file
View File

@ -0,0 +1,230 @@
#include <fs/ramfs.h>
#include <stdlib.h>
#include <string.h>
#include <fs/vfs.h>
/*
Note: the special FILE value -128 means the current directory.
-32 means stdin
-33 means stdout (which can be read)
*/
bool vfs_initialized = false;
ramfs_file_header_t* vfs_current_dir = NULL;
void vfs_init(void)
{
if (!vfs_initialized)
{
ramfs_init();
ramfs_make_root();
vfs_initialized = true;
vfs_current_dir = ramfs_get_root();
}
}
/* ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent); */
FILE create_file(char* filename, char type, char encryption, FILE parent)
{
if (!filename)
{
return -1;
}
if (parent == -128)
{
parent = vfs_current_dir->fd;
}
ramfs_file_header_t* file = ramfs_create_file(filename, type, encryption, ramfs_resolve_fd(parent));
if (!file)
{
return -4; /* error code for failed creation */
}
return file->fd;
}
int32_t delete_file(FILE file)
{
/*
XXX WARNING: ANY AND ALL PROCESSES CAN DELETE A FILE VIA THIS INTERFACE!!! XXX
XXX THIS MUST BE PACHED SOON!!! OR AT LEAST ADD PERMISSION CHECKING IN THE SYSCALL INTERFACE XXX
XXX OR IN THE C LIBRARIES!!! XXX
*/
if (file < 1)
{
return -4;
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
return ramfs_delete_file(_file);
}
/*
Open a file based on a string.
Return a file descriptor on success, a negative value on failure.
return values:
(positive non-zero value) - File descriptor
-1 - Insufficient permissions to open file
-2 - File does not exist ( or at least, File not found. )
-3 - No filesystem is initialized
-4 - Internal error, perhaps try again
*/
FILE open_file(char* filename)
{
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_path(filename);
if (!_file)
{
return (FILE)-2;
}
return (FILE)_file->fd;
}
return (FILE)-3;
}
FILE write_file(FILE file, void* data, size_t len)
{
if (file < 1 || !data || len == 0)
{
return file;
}
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file)
{
return -4;
}
if (_file->type == RAMFS_FILE_DIR)
{
return -1;
}
if (_file->data_begin)
{
free(_file->data_begin);
_file->data_begin = NULL;
_file->data_end = NULL;
}
void* new_buf = malloc(len);
if (!new_buf)
{
return -2;
}
memcpy(new_buf, data, len);
_file->data_begin = new_buf;
_file->data_end = (void*)((uint8_t*)new_buf + len);
return file;
}
return -3;
}
int32_t read_file(FILE file, void* buf, size_t buflen)
{
if (file < 1 || !buf || buflen == 0)
{
return -1; /* Invalid arguments */
}
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file || _file->type == RAMFS_FILE_DIR)
{
return -2; /* Not a file or trying to read a directory */
}
if (!_file->data_begin || !_file->data_end)
{
return 0; /* Empty file */
}
size_t total_len = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
if (_file->read_offset >= (int32_t)total_len)
{
return 0; /* End of file */
}
size_t available = total_len - _file->read_offset;
size_t to_copy = (buflen < available) ? buflen : available;
memcpy(buf, (uint8_t*)_file->data_begin + _file->read_offset, to_copy);
_file->read_offset += to_copy;
return (int32_t)to_copy;
}
return -3; /* FS not initialized */
}
int32_t reset_read_offset(FILE file)
{
if (file < 1)
{
return -1;
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file)
{
return -2;
}
_file->read_offset = 0;
return 0;
}
int32_t seek_file(FILE file, int32_t offset)
{
if (file < 0 && file != -32 && file != -33)
{
return -1; /* Invalid file descriptor */
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file || _file->type == RAMFS_FILE_DIR)
return -2; // Invalid file or directory
if (!_file->data_begin || !_file->data_end)
return -3; // Empty file
size_t file_size = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
if (offset < 0 || (size_t)offset > file_size)
return -4; // Offset out of bounds
_file->read_offset = offset;
return 0; // Success
}

View File

@ -1,35 +1,38 @@
#include <stdio.h> #include <stdio.h>
#include <drivers/pit.h>
#include <port_io.h> #include <port_io.h>
#include <drivers/ide.h> #include <drivers/ide.h>
static void io_delay() { static int32_t ide_wait(uint16_t io, int32_t check_drq)
for (int32_t i = 0; i < 1000; i++) { {
outb(0x80, 0); for (int32_t i = 0; i < 5000; i++)
{
uint8_t status = inb(io + ATA_REG_STATUS);
if (!(status & ATA_SR_BSY))
{
if (!check_drq || (status & ATA_SR_DRQ))
{
return 0;
}
} }
pit_sleep(4);
}
return 1;
} }
static int32_t ide_wait_ready(uint16_t io)
static int32_t ide_wait(uint16_t io, int32_t check_drq) { {
for (int32_t i = 0; i < 5000; i++) { for (int32_t i = 0; i < 100000; i++)
uint8_t status = inb(io + ATA_REG_STATUS); {
if (!(status & ATA_SR_BSY)) { uint8_t status = inb(io + ATA_REG_STATUS);
if (!check_drq || (status & ATA_SR_DRQ)) if (!(status & ATA_SR_BSY))
return 0; {
} return 0;
io_delay(1);
} }
return 1; }
} return 1;
static int32_t ide_wait_ready(uint16_t io) {
for (int32_t i = 0; i < 100000; i++) {
uint8_t status = inb(io + ATA_REG_STATUS);
if (!(status & ATA_SR_BSY)) return 0;
}
return 1;
} }

View File

@ -1,11 +1,9 @@
#include <stdio.h> #include <stdio.h>
#include <drivers/ps2_keyboard.h> #include <drivers/ps2_keyboard.h>
#include <drivers/pit.h>
#include <drivers/irq.h> #include <drivers/irq.h>
static void pit_handler(void)
{
}
void irq_handler(uint8_t irq_number) void irq_handler(uint8_t irq_number)
{ {

View File

@ -1,32 +1,43 @@
/*#include <stdint.h> #include <types.h>
#include <port_io.h> #include <port_io.h>
#include <drivers/irq.h> #include <stdio.h>
#define PIT_CHANNEL0 0x40 #include <drivers/pit.h>
#define PIT_COMMAND 0x43
#define PIT_FREQUENCY 1193182
static uint32_t tick = 0;
void pit_callback(struct regs* r) #define PIT_CHANNEL0 0x40
#define PIT_COMMAND 0x43
#define PIT_IRQ_LINE 0
#define PIT_FREQUENCY_BASE 1193182
volatile uint64_t pit_ticks = 0;
bool pit_initialized = false;
void pit_init(void)
{ {
(void)r; uint16_t divisor = (uint16_t)1193;
tick++;
/* Send command byte */
outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */
/* Send divisor low and high byte */
outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF)); /* Low byte */
outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF)); /* High byte */
pit_initialized = true;
} }
void pit_init(uint32_t frequency) void pit_handler(void)
{ {
uint32_t divisor = PIT_FREQUENCY / frequency; pit_ticks++;
outb(PIT_COMMAND, 0x36);
outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF));
outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF));
register_interrupt_handler(32, pit_callback);
} }
void sleep(uint32_t milliseconds) void pit_sleep(uint64_t ms)
{ {
uint32_t target = tick + milliseconds; uint64_t target = pit_ticks + ms;
while (tick < target); while (pit_ticks < target)
}*/ {
asm volatile ("hlt");
}
}

View File

@ -1,6 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <port_io.h> #include <port_io.h>
#include <tty.h> #include <tty.h>
#include <stdlib.h>
#include <drivers/ps2_keyboard.h> #include <drivers/ps2_keyboard.h>
@ -27,10 +28,20 @@
#define KEYBOARD_IRQ 1 #define KEYBOARD_IRQ 1
bool ps2keyboard_initialized = false;
/* State for shift key */ /* State for shift key */
static bool shift_pressed = false; static bool shift_pressed = false;
/* State for caps-lock key */
static bool capslock_pressed = false;
volatile char current_char;
volatile char* current_string = NULL;
volatile int32_t current_length = 0;
volatile int32_t capacity = 0;
static const char scancode_map[128] = { static const char scancode_map[128] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */ 0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */
'\t', // Tab '\t', // Tab
@ -51,6 +62,55 @@ static const char scancode_map[128] = {
void keyboard_init(void) void keyboard_init(void)
{ {
outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */ outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */
ps2keyboard_initialized = true;
}
char get_char(void)
{
return current_char;
}
char* get_string(void)
{
return current_string;
}
static void append_char(char c)
{
if (current_length + 1 >= capacity)
{
/* Need more space (+1 for '\0') */
int new_capacity = (capacity == 0) ? 16 : capacity * 2;
char* new_str = (char*)malloc(new_capacity);
if (!new_str) {
return;
}
if (current_string)
{
memcpy(new_str, current_string, current_length);
free(current_string);
}
current_string = new_str;
capacity = new_capacity;
}
current_string[current_length] = c;
current_length++;
current_string[current_length] = '\0'; /* Maintain null terminator */
}
static void free_current_string(void)
{
if (current_string)
{
free(current_string);
current_string = NULL;
current_length = 0;
capacity = 0;
}
} }
void keyboard_handler(void) { void keyboard_handler(void) {
@ -67,6 +127,12 @@ void keyboard_handler(void) {
shift_pressed = false; shift_pressed = false;
return; return;
} }
else if (scancode == 0x3A)
{
capslock_pressed = !capslock_pressed;
return;
}
if (scancode & 0x80) if (scancode & 0x80)
{ {
@ -74,7 +140,7 @@ void keyboard_handler(void) {
} else } else
{ {
char c = scancode_map[scancode]; char c = scancode_map[scancode];
if (shift_pressed && c >= 'a' && c <= 'z') { if ((shift_pressed ^ capslock_pressed) && c >= 'a' && c <= 'z') {
c -= 32; /* Convert to uppercase */ c -= 32; /* Convert to uppercase */
} }
else if (shift_pressed) else if (shift_pressed)
@ -84,7 +150,17 @@ void keyboard_handler(void) {
if (c) if (c)
{ {
printf("%c", c); current_char = c;
if (c == '\n')
{
free_current_string();
}
else
{
append_char(c);
printf("%c", c);
}
} }
} }
} }

View File

@ -1,21 +0,0 @@
/*#include <drivers/isr.h>
#include <drivers/irq.h>
#include <drivers/timer.h>
volatile uint32_t tick_count = 0;
void irq0_handler(regs_t* regs)
{
tick_count++;
}
void timer_sleep(uint32_t ms)
{
uint32_t target = tick_count + ms;
while (tick_count < target)
{
asm volatile("hlt");
}
}
*/

View File

@ -208,7 +208,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
unsigned char syms1[] = { ',', '.', '/', ';', '\'', '[', ']', '`', '-', '=', '\\', '\0' }; unsigned char syms1[] = { ',', '.', '/', ';', '\'', '[', ']', '`', '-', '=', '\\', '\0' };
unsigned char syms2[] = { '<', '>', '?', ':', '\"', '{', '}', '~', '_', '+', '|', '\0' }; unsigned char syms2[] = { '<', '>', '?', ':', '\"', '{', '}', '~', '_', '+', '|', '\0' };
for (int32_t i = 0; i < (int32_t)(strlen((char*)lowerc) - 1); ++i) for (int32_t i = 0; i < (int32_t)(strlen((char*)lowerc)); ++i)
{ {
if (uc == lowerc[i]) if (uc == lowerc[i])
{ {
@ -220,7 +220,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
} }
} }
for (int32_t i = 0; i < (int32_t)(strlen((char*)nums) - 1); ++i) for (int32_t i = 0; i < (int32_t)(strlen((char*)nums)); ++i)
{ {
if (uc == nums[i]) if (uc == nums[i])
{ {
@ -232,7 +232,7 @@ unsigned char terminal_get_shifted(unsigned char uc)
} }
} }
for (int32_t i = 0; i < (int32_t)(strlen((char*)syms1) - 1); ++i) for (int32_t i = 0; i < (int32_t)(strlen((char*)syms1)); ++i)
{ {
if (uc == syms1[i]) if (uc == syms1[i])
{ {

View File

@ -3,7 +3,10 @@
#include <types.h> #include <types.h>
void pit_init(uint32_t freq); extern volatile uint64_t pit_ticks;
void sleep(uint32_t millis);
void pit_init(void);
void pit_handler(void);
void pit_sleep(uint64_t ms);
#endif #endif

View File

@ -6,4 +6,7 @@
void keyboard_init(void); void keyboard_init(void);
void keyboard_handler(void); void keyboard_handler(void);
char get_char(void);
char* get_string(void);
#endif #endif

View File

@ -1,11 +0,0 @@
#ifndef _TIMER_H
#define _TIMER_H
#include <stdint.h>
extern volatile uint32_t tick_count;
void timer_sleep(uint32_t ms);
void pit_init(uint32_t frequency);
#endif

View File

@ -1,79 +1,8 @@
#ifndef _DUCKFS_H #ifndef _DUCKFS_H
#define _DUCKFS_H #define _DUCKFS_H
#include <stdint.h> #include <types.h>
#define DFS_MAGIC 0xDF1984CC void duckfs_init(void);
#define DFS_BLOCK_SIZE 512
#define DFS_VERSION_0 "DuckFS, wheresDax?"
#define DFS_VERSION_1 "DuckFS, Terminator"
#define DFS_VERSION_2 "DuckFS-Terminator2"
#define DFS_VERSION_3 "DuckFS,StarWarsEIV"
#define DFS_VERSION_4 "DuckFS QUACK,QUACK"
#define DFS_FILE_ERROR -8
#define DFS_FILE_UNUSED -1
#define DFS_FILE_USED 0
#define DFS_FILE_TEXT 0
#define DFS_FILE_BINARY 1
#define DFS_FILE_DIRECTORY 2
/* encryption algorithms */
#define DFS_CAESAR_5 88
#define DFS_CAESAR_8 84
#define DFS_CAESAR_2 09
#define DFS_QUACK_32 99
#define DFS_MAX_FILENAME_LEN 64
#define DFS_MAX_FILES 256
typedef struct duckfs_file_header {
char filename[DFS_MAX_FILENAME_LEN + 1]; /* + 1 for the \0 */
char permissions[3]; /* Same thing here */
/*
512 Bytes per sector, meaning a 2 sector file is 1024 bytes, or 1 KiB.
Only valid if this file is not a directory.
*/
int32_t num_sectors;
int16_t type; /* Indicates the file type. -1 for null file, 0 for a text file, 1 for a binary file, and 2 for a directory. */
uint16_t _reserved0; /* (align to 4) */
struct duckfs_file_header* next;
struct duckfs_file_header* prev;
struct duckfs_file_header* contents; /* contains the directories files. only valid if this file is a directory. */
uint32_t lba_start; /* only is valid if this file is not a directory. */
uint32_t lba_end; /* only is valid if this file is not a directory. */
uint8_t _reserved1[158]; /* padding to 256 bytes total */
} duckfs_file_header_t;
typedef struct duckfs_superblock {
int32_t duckfs_magic; /* must be DFS_MAGIC. */
char duckfs_version_string[19];
char volume_label[19]; /* 18 characters and a null zero. */
int16_t encryption;
struct duckfs_file_header* duckfs_root;
uint32_t _padding[116];
} duckfs_superblock_t;
int32_t duckfs_init(int16_t drive);
void duckfs_format(int16_t drive);
int32_t duckfs_makedir(const char* filename, const char* perms);
void duckfs_free_directory(duckfs_file_header_t* dir);
duckfs_file_header_t duckfs_create_entry(const char* name, const char* perms, const char* type);
bool duckfs_add_entry(duckfs_file_header_t* dir, duckfs_file_header_t* entry);
#endif #endif

View File

@ -1,53 +1,56 @@
#ifndef _RAM_FS_H #ifndef _RAM_FS_H
#define _RAM_FS_H #define _RAM_FS_H
#include <stdint.h> #include <types.h>
#include <stdbool.h>
#define RAMFS_FILENAME_LEN 32
#define RAMFS_MAX_FILES 128
#define RAMFS_BLOCK_SIZE 4096
#define RAMFS_MAX_PATH_LEN 255
#define RAMFS_PERM_READ 0x01 #define RAMFS_PERM_READ 0x01
#define RAMFS_PERM_WRITE 0x02 #define RAMFS_PERM_WRITE 0x02
#define RAMFS_PERM_EXEC 0x04 #define RAMFS_PERM_EXEC 0x04
#define RAMFS_PERM_ALL (RAMFS_PERM_READ | RAMFS_PERM_WRITE | RAMFS_PERM_EXEC) #define RAMFS_PERM_ALL (RAMFS_PERM_READ | RAMFS_PERM_WRITE | RAMFS_PERM_EXEC)
typedef struct ramfs_file { #define RAMFS_FILE_DIR 'd'
char name[RAMFS_MAX_PATH_LEN]; #define RAMFS_FILE_TEXT 't'
uint32_t size; #define RAMFS_FILE_BINARY 'b'
uint8_t* data; #define RAMFS_FILE_LINK 'l'
uint8_t permissions; #define RAMFS_FILE_NOFILE 'n'
} ramfs_file_t;
typedef struct ramfs_directory { #define RAMFS_ENCR_NONE 'n'
char name[RAMFS_MAX_PATH_LEN]; #define RAMFS_ENCR_SIMPLE 's'
ramfs_file_t* files[RAMFS_MAX_FILES];
uint32_t file_count;
} ramfs_directory_t;
typedef struct ramfs_file_header {
char filename[RAMFS_FILENAME_LEN + 1];
char type;
char encryption;
struct ramfs_file_header* content;
struct ramfs_file_header* parent;
struct ramfs_file_header* next;
struct ramfs_file_header* link_target;
void* data_begin;
void* data_end;
int32_t read_offset;
int32_t fd;
} ramfs_file_header_t;
void ramfs_init(); void ramfs_init(void);
ramfs_file_t* ramfs_create_file(const char* name, uint32_t size, uint8_t permissions); ramfs_file_header_t* ramfs_make_root(void);
bool ramfs_delete_file(const char* name); ramfs_file_header_t* ramfs_get_root(void);
ramfs_file_t* ramfs_find_file(const char* name); int32_t ramfs_get_files(void);
bool ramfs_get_initialized(void);
bool ramfs_create_directory(const char* name); ramfs_file_header_t* ramfs_resolve_path(const char* path);
bool ramfs_delete_directory(const char* name); ramfs_file_header_t* ramfs_resolve_fd_dir(ramfs_file_header_t* current, int32_t fd);
ramfs_file_header_t* ramfs_resolve_fd(int32_t fd);
bool ramfs_check_permissions(const char* name, uint8_t required_permissions); ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent);
int32_t ramfs_delete_file(ramfs_file_header_t* file);
bool ramfs_resize_file(const char* name, uint32_t new_size); ramfs_file_header_t* ramfs_write_file(ramfs_file_header_t* file, void* data, size_t len);
bool ramfs_append_to_file(const char* name, const uint8_t* data, uint32_t data_size); int32_t ramfs_read_file(ramfs_file_header_t* file, void* buffer, size_t buffer_len);
bool ramfs_read_file(const char* name, uint8_t* buffer, uint32_t buffer_size);
bool ramfs_write_file(const char* name, const uint8_t* data, uint32_t size);
bool ramfs_overwrite_file(const char* name, const uint8_t* data, uint32_t size);
void ramfs_list_files();
void ramfs_list_directories();
#endif #endif

20
include/fs/vfs.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _VFS_H
#define _VFS_H
#include <types.h>
typedef int32_t FILE;
void vfs_init(void);
FILE create_file(char* filename, char type, char encryption, FILE parent);
int32_t delete_file(FILE file);
FILE open_file(char* filename);
FILE write_file(FILE file, void* data, size_t len);
int32_t read_file(FILE file, void* buf, size_t buflen);
int32_t reset_read_offset(FILE file);
#endif

View File

@ -1,2 +1,10 @@
#ifndef STDIO_H
#define STDIO_H
#include <types.h>
#include <printf.h> #include <printf.h>
char getchar(void);
char* getstring(void);
#endif

View File

@ -1,9 +1,12 @@
#ifndef STDLIB_H #ifndef STDLIB_H
#define STDLIB_H #define STDLIB_H
#include <types.h>
#include <mm/mm.h> #include <mm/mm.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <types.h>
void sleep(uint64_t millis);
#endif #endif

View File

@ -11,6 +11,9 @@ int32_t strncmp(const char *s1, const char *s2, size_t n);
size_t strcpy(char *dst, const char *src); size_t strcpy(char *dst, const char *src);
char *strncpy(char *dest, const char *src, uint32_t n); char *strncpy(char *dest, const char *src, uint32_t n);
void strcat(char *dest, const char *src); void strcat(char *dest, const char *src);
char* strdup(const char* s);
char* strtok(char* str, const char* delim);
char* strchr(const char* s, int c);
int32_t ischar(int32_t c); int32_t ischar(int32_t c);
int32_t isspace(char c); int32_t isspace(char c);

View File

@ -25,12 +25,13 @@
#include <stdio.h> #include <stdio.h>
#include <drivers/pci.h> #include <drivers/pci.h>
#include <drivers/ps2_keyboard.h> #include <drivers/ps2_keyboard.h>
#include <drivers/pit.h>
/*#include <drivers/ahci.h>*/ /*#include <drivers/ahci.h>*/
#include <drivers/ide.h> #include <drivers/ide.h>
#include <mm/mm.h> #include <mm/mm.h>
#include <fs/ramfs.h>
#include <fs/fat32.h> #include <fs/fat32.h>
#include <fs/duckfs.h> #include <fs/duckfs.h>
#include <fs/vfs.h>
#include <vector_extentions/sse.h> #include <vector_extentions/sse.h>
@ -106,6 +107,10 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
printd("SSE test succeeded\n"); printd("SSE test succeeded\n");
} }
printd("Initializing the PIT...\n");
pit_init();
printd("PIT initialized\n");
printd("Initializing the PS/2 keyboard...\n"); printd("Initializing the PS/2 keyboard...\n");
keyboard_init(); keyboard_init();
printd("PS/2 Keyboard initialized\n"); printd("PS/2 Keyboard initialized\n");
@ -116,33 +121,66 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic)
printd("AHCI initialized\n"); printd("AHCI initialized\n");
*/ */
/*printd("Initializing RAMFS...\n"); printd("Initializing VFS...\n");
ramfs_init(); vfs_init();
printd("RAMFS initialized.\n");*/ printd("VFS initialized.\n");
printd("Initializing IDE system...\n"); printd("Initializing IDE system...\n");
ide_initialize(); ide_initialize();
printd("IDE initialized\n"); printd("IDE initialized\n");
/*printd("Initializing DuckFS...\n"); /*printd("Initializing DuckFS...\n");
int32_t duckfs_init_rv = duckfs_init(0); duckfs_init();
printf("[ DEBUG ] DuckFS initialized with RV %d\n", duckfs_init_rv);*/ printd("DuckFS initialized\n");*/
/*printd("Initializing FAT32...\n"); /*printd("Initializing FAT32...\n");
fat32_init(0); fat32_init(0);
printd("FAT32 initialized\n");*/ printd("FAT32 initialized\n");*/
/*printd("Initializing the PIT...\n");
pit_init(1000);
printd("PIT initialized\n");*/
/* --- END INITIALIZATION SECTION --- */ /* --- END INITIALIZATION SECTION --- */
terminal_setcolor(VGA_COLOR_LIGHT_GREEN); terminal_setcolor(VGA_COLOR_LIGHT_GREEN);
/*sleep(1000);*/
//begin_anim(espresso_kernel_version); /*pit_sleep(4000);
begin_anim(espresso_kernel_version);*/
printf("Creating file via VFS...\n");
FILE file = create_file("test.txt", 't', 'n', -128);
printf("file = %d\n", file);
char buf[32] = "Hello from VFS";
char bufr[32] = { 0 };
write_file(file, buf, strlen(buf));
read_file(file, bufr, sizeof(bufr));
printf("Read data: %s\n", bufr);
/*printf("Creating file...\n");
ramfs_file_header_t* fil = ramfs_create_file("text", "txt", 't', 'n', ramfs_get_root());
if (!fil)
{
printf("File creation failed!\n");
return;
}
printf("File created\n");
char buf[32] = "hello from RAMFS";
char bufr[32] = { 0 };
ramfs_write_file(fil, buf, strlen(buf));
ramfs_read_file(fil, bufr, sizeof(bufr));
printf("Read data: %s\n", bufr);*/
printf("Guten tag and welcome to Espresso\n"); printf("Guten tag and welcome to Espresso\n");

View File

@ -1,190 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fs/ramfs.h>
static ramfs_file_t ramfs_files[RAMFS_MAX_FILES];
static ramfs_directory_t root_directory = { .name = "/", .file_count = 0 };
void ramfs_init()
{
memset(ramfs_files, 0, sizeof(ramfs_files));
root_directory.file_count = 0;
}
ramfs_file_t* ramfs_create_file(const char* name, uint32_t size, uint8_t permissions)
{
for (uint32_t i = 0; i < RAMFS_MAX_FILES; i++) {
if (ramfs_files[i].name[0] == '\0') {
// Create the file
ramfs_file_t* file = &ramfs_files[i];
strncpy(file->name, name, RAMFS_MAX_PATH_LEN);
file->size = size;
file->data = (size > 0) ? malloc(size) : NULL;
file->permissions = permissions;
if (root_directory.file_count < RAMFS_MAX_FILES) {
root_directory.files[root_directory.file_count++] = file;
}
return file;
}
}
return NULL;
}
bool ramfs_delete_file(const char* name)
{
for (uint32_t i = 0; i < root_directory.file_count; i++) {
if (strcmp(root_directory.files[i]->name, name) == 0) {
free(root_directory.files[i]->data);
root_directory.files[i] = root_directory.files[root_directory.file_count - 1];
root_directory.file_count--;
return true;
}
}
return false;
}
ramfs_file_t* ramfs_find_file(const char* name)
{
for (uint32_t i = 0; i < root_directory.file_count; i++) {
if (strcmp(root_directory.files[i]->name, name) == 0) {
return root_directory.files[i];
}
}
return NULL;
}
bool ramfs_resize_file(const char* name, uint32_t new_size)
{
ramfs_file_t* file = ramfs_find_file(name);
if (file)
{
file->data = realloc(file->data, new_size);
file->size = new_size;
return true;
}
return false;
}
bool ramfs_append_to_file(const char* name, const uint8_t* data, uint32_t data_size)
{
ramfs_file_t* file = ramfs_find_file(name);
if (file && (file->permissions & RAMFS_PERM_WRITE))
{
file->data = realloc(file->data, file->size + data_size + 1);
if (!file->data) return false;
memcpy(file->data + file->size, data, data_size);
file->size += data_size;
file->data[file->size] = '\0';
return true;
}
return false;
}
bool ramfs_create_directory(const char* name)
{
if (root_directory.file_count < RAMFS_MAX_FILES) {
ramfs_directory_t* dir = (ramfs_directory_t*)malloc(sizeof(ramfs_directory_t));
strncpy(dir->name, name, RAMFS_MAX_PATH_LEN);
dir->file_count = 0;
root_directory.files[root_directory.file_count++] = (ramfs_file_t*)dir;
return true;
}
return false;
}
bool ramfs_delete_directory(const char* name)
{
for (uint32_t i = 0; i < root_directory.file_count; i++) {
if (strcmp(root_directory.files[i]->name, name) == 0) {
// Delete the directory (along with its files)
ramfs_directory_t* dir = (ramfs_directory_t*)root_directory.files[i];
for (uint32_t j = 0; j < dir->file_count; j++) {
free(dir->files[j]->data);
}
free(dir);
root_directory.files[i] = root_directory.files[root_directory.file_count - 1];
root_directory.file_count--;
return true;
}
}
return false;
}
bool ramfs_check_permissions(const char* name, uint8_t required_permissions)
{
ramfs_file_t* file = ramfs_find_file(name);
if (file) {
return (file->permissions & required_permissions) == required_permissions;
}
return false;
}
void ramfs_list_files()
{
printf("Files in RAMFS:\n");
for (uint32_t i = 0; i < root_directory.file_count; i++) {
printf("%s (Size: %u bytes)\n", root_directory.files[i]->name, root_directory.files[i]->size);
}
}
void ramfs_list_directories()
{
printf("Directories in RAMFS:\n");
for (uint32_t i = 0; i < root_directory.file_count; i++) {
if (root_directory.files[i]->data != NULL) {
printf("%s\n", root_directory.files[i]->name);
}
}
}
bool ramfs_read_file(const char* name, uint8_t* buffer, uint32_t buffer_size)
{
ramfs_file_t* file = ramfs_find_file(name);
if (file && (file->permissions & RAMFS_PERM_READ))
{
uint32_t bytes_to_read = (file->size < buffer_size) ? file->size : buffer_size;
memcpy(buffer, file->data, bytes_to_read);
return true;
}
return false;
}
bool ramfs_write_file(const char* name, const uint8_t* data, uint32_t size)
{
return ramfs_append_to_file(name, data, size);
}
bool ramfs_overwrite_file(const char* name, const uint8_t* data, uint32_t size)
{
ramfs_file_t* file = ramfs_find_file(name);
if (!file || !(file->permissions & RAMFS_PERM_WRITE)) {
return false;
}
// Allocate space for data + null terminator
uint8_t* new_data = realloc(file->data, size + 1);
if (!new_data && size > 0) {
return false; // realloc failed
}
file->data = new_data;
if (size > 0 && data) {
memcpy(file->data, data, size);
}
file->data[size] = '\0'; // Ensure null-terminated
file->size = size;
return true;
}

View File

@ -69,7 +69,7 @@ void* calloc(size_t nmemb, size_t size)
void* ptr = malloc(total); void* ptr = malloc(total);
if (ptr) if (ptr)
{ {
memset(ptr, 0, total); memset(ptr, 0, total);
} }
return ptr; return ptr;
} }

62
lib/stdio.c Normal file
View File

@ -0,0 +1,62 @@
#include <drivers/ps2_keyboard.h>
#include <fs/vfs.h>
#include <stdio.h>
extern bool ps2keyboard_initialized;
char getchar(void)
{
if (ps2keyboard_initialized)
{
return get_char();
}
return '\0';
}
char* getstring(void)
{
if (ps2keyboard_initialized)
{
return get_string();
}
return "HELLO\0";
}
char* fgets(char* buf, int n, FILE file)
{
if (!buf || n <= 1 || file < 1)
{
return NULL;
}
int total_read = 0;
char c;
while (total_read < n - 1)
{
int bytes = read_file(file, &c, 1);
if (bytes <= 0)
{
break; /* EOF or error */
}
buf[total_read++] = c;
if (c == '\n')
{
break; /* Stop at newline */
}
}
if (total_read == 0)
{
return NULL; /* Nothing read (e.g. EOF) */
}
buf[total_read] = '\0';
return buf;
}

13
lib/stdlib.c Normal file
View File

@ -0,0 +1,13 @@
#include <drivers/pit.h>
#include <stdlib.h>
extern bool pit_initialized;
void sleep(uint64_t millis)
{
if (pit_initialized)
{
pit_sleep(millis);
}
}

View File

@ -1,6 +1,8 @@
#include <stdlib.h>
#include <vector_extentions/sse.h>
#include <string.h> #include <string.h>
#include <vector_extentions/sse.h>
extern int16_t sse_initialized; extern int16_t sse_initialized;
@ -77,6 +79,82 @@ void strcat(char *dest, const char *src)
*end = '\0'; *end = '\0';
} }
char* strdup(const char* s)
{
if (!s)
{
return NULL;
}
size_t len = strlen(s);
char* copy = (char*)malloc(len + 1);
if (!copy)
{
return NULL;
}
memcpy(copy, s, len);
copy[len] = '\0';
return copy;
}
char* strtok(char* str, const char* delim)
{
static char* next_token = NULL;
if (str != NULL)
{
next_token = str;
}
else if (next_token == NULL)
{
return NULL;
}
while (*next_token && strchr(delim, *next_token))
{
next_token++;
}
if (*next_token == '\0')
{
return NULL;
}
char* token_start = next_token;
while (*next_token && !strchr(delim, *next_token))
{
next_token++;
}
if (*next_token)
{
*next_token = '\0';
next_token++;
}
return token_start;
}
char* strchr(const char* s, int c)
{
while (*s)
{
if (*s == (char)c)
{
return (char*)s;
}
s++;
}
return NULL;
}
void *memset(void *dst, char c, uint32_t n) void *memset(void *dst, char c, uint32_t n)
{ {
char *temp = dst; char *temp = dst;