REF: Renamed kernel -> System; userspace -> Runtime; bootloader -> Boot

del: KSH
This commit is contained in:
Karina
2026-04-04 19:44:39 +04:00
parent 2f58f64175
commit 47735bb1bd
117 changed files with 10 additions and 274 deletions
+13
View File
@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.20)
project(termOSuserspace LANGUAGES C ASM_NASM)
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
message(STATUS "Building termOS's userspace")
add_subdirectory(libterm)
add_subdirectory(init)
add_subdirectory(debug)
add_subdirectory(termosh)
+6
View File
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(termOSdbg LANGUAGES C)
file(GLOB_RECURSE debug_SOURCES "src/*.c")
add_termos_executable(debug "${debug_SOURCES}")
+12
View File
@@ -0,0 +1,12 @@
#include <termOS.h>
int main() {
for (int i = 0; i < 100; i++) {
UInt64 pid = ProcessSpawn("/System/CoreServices/debug");
if (pid < 0) {
ConsolePrint("[PIDSPAMMER] Error %d\n", pid);
} else {
ConsolePrint("[PIDSPAMMER] %d spawned\n", pid);
}
}
}
+6
View File
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(termOSinit LANGUAGES C)
file(GLOB_RECURSE INIT_SOURCES "src/*.c")
add_termos_executable(init "${INIT_SOURCES}")
+13
View File
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <termOS.h>
// TODO: read .cfg and spawn what stated there
int main() {
while (1) {
Int32 pid = ProcessSpawn("/System/CoreServices/termosh");
if (pid < 0) return pid;
ProcessWait(pid);
}
}
+68
View File
@@ -0,0 +1,68 @@
cmake_minimum_required(VERSION 3.16)
project(libterm LANGUAGES C ASM_NASM)
set(USER_C_FLAGS
-ffreestanding
-fno-builtin
-Wno-incompatible-library-redeclaration # stfu
-nostdlib
-nostdinc
-fno-stack-protector
-fno-pic
-fno-pie
-m64
-mno-red-zone
-mcmodel=small
-Wall
-Wextra
-Werror
-O2
)
set(CMAKE_ASM_NASM_FLAGS "-f elf64")
set(LIBTERM_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/OSServices.asm
${CMAKE_CURRENT_SOURCE_DIR}/src/Console.c
${CMAKE_CURRENT_SOURCE_DIR}/src/Memory.c
${CMAKE_CURRENT_SOURCE_DIR}/src/String.c
${CMAKE_CURRENT_SOURCE_DIR}/src/Character.c
${CMAKE_CURRENT_SOURCE_DIR}/src/Process.c
)
add_library(term STATIC ${LIBTERM_SOURCES})
target_compile_options(term PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
target_include_directories(term PUBLIC inc)
add_library(RuntimeEntryObject OBJECT src/RuntimeEntry.asm)
target_compile_options(RuntimeEntryObject PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
function(add_termos_executable NAME SOURCES)
add_executable(${NAME} ${SOURCES})
target_sources(${NAME} PRIVATE $<TARGET_OBJECTS:RuntimeEntryObject>)
target_compile_options(${NAME} PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>
-fno-stack-protector) # fixme: what the fuck. ugly this works user_c_flags apparently not
target_link_libraries(${NAME} PRIVATE term)
target_link_options(${NAME} PRIVATE
-T ${libterm_SOURCE_DIR}/linker.ld
-nostdlib
-static
)
set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot")
set(STARTUP_VOLUME_DIR "${CMAKE_BINARY_DIR}/StartupVolume/System/CoreServices")
file(MAKE_DIRECTORY "${STARTUP_VOLUME_DIR}")
set(FINAL_HOT_PATH "${STARTUP_VOLUME_DIR}/${NAME}")
add_custom_command(TARGET ${NAME} POST_BUILD
COMMAND cargo run --release --quiet -- $<TARGET_FILE:${NAME}> ${FINAL_HOT_PATH}
WORKING_DIRECTORY ${ELF2HOT_DIR}
COMMENT "elf2hot: Converting ${NAME} to HOT! format..."
VERBATIM
)
endfunction()
+15
View File
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <Types.h>
enum {
kConsoleEOF = -1,
kConsoleDefaultBufferSize = 1024
};
Int32 ConsolePrint(const char* format, ...);
Int32 StringFormat(char* destination, UInt64 size, const char* format, ...);
Int32 ConsoleGetCharacter();
char* ConsoleReadLine(char* string, UInt64 size);
+23
View File
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <Types.h>
enum {
kMemoryBlockMagic = 0x1CE1CE,
kMemoryAlignment = 16,
kMemoryPageSize = 4096
};
typedef struct MemoryBlockHeader {
UInt64 magic;
struct MemoryBlockHeader* next;
struct MemoryBlockHeader* previous;
UInt64 size;
bool isFree;
} MemoryBlockHeader;
void* MemoryAllocate(UInt64 size);
void MemoryFree(void* pointer);
void* MemoryReallocate(void* pointer, UInt64 newSize);
+8
View File
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <Types.h>
Int32 ProcessSpawn(const char* path);
Int32 ProcessWait(UInt64 pid);
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include <Types.h>
void* MemorySet(void* destination, UInt8 value, UInt64 count);
void* MemoryCopy(void* destination, const void* source, UInt64 count);
Int32 StringCompare(const char* firstString, const char* secondString);
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit);
char* StringCopy(char* destination, const char* source);
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit);
UInt64 StringGetLength(const char* string);
UInt64 StringGetInitialSpan(const char* string, const char* characterSet);
char* StringFindFirstCharacterFromSet(const char* string, const char* accept);
char* StringTokenize(char *s, const char* delim);
+23
View File
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
typedef unsigned char UInt8;
typedef unsigned short UInt16;
typedef unsigned int UInt32;
typedef unsigned long long UInt64;
typedef signed char Int8;
typedef signed short Int16;
typedef signed int Int32;
typedef signed long long Int64;
typedef UInt64 usize;
typedef UInt64 uintptr_t;
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#endif
+8
View File
@@ -0,0 +1,8 @@
#pragma once
typedef __builtin_va_list va_list;
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
#define va_copy(d, s) __builtin_va_copy(d, s)
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <Console.h>
#include <Memory.h>
#include <Process.h>
#include <String.h>
#include <Varargs.h>
#include <Types.h>
+35
View File
@@ -0,0 +1,35 @@
ENTRY(_start)
SECTIONS
{
. = 0x400000;
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
*(COMMON)
}
/DISCARD/ : {
*(.note.gnu.build-id)
*(.note.GNU-stack)
*(.note.gnu.property)
*(.comment)
*(.interp)
*(.dynsym)
*(.dynstr)
*(.hash)
*(.gnu.hash)
}
}
View File
+156
View File
@@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <Console.h>
#include <Varargs.h>
#include <String.h>
extern UInt64 OSServiceIORead(UInt64 fileDescriptor, void* buffer, UInt64 length);
extern UInt64 OSServiceIOWrite(UInt64 fileDescriptor, const void* buffer, UInt64 length);
static void sConsoleWriteCharacter(char character) {
OSServiceIOWrite(1, &character, 1);
}
static inline void sConsoleBufferAdd(char* string, UInt64 size, UInt64* written, char character) {
if (*written < size - 1 && size > 0) {
string[*written] = character;
}
(*written)++;
}
static Int32 sStringFormatVariadic(char* string, UInt64 size, const char* format, va_list args) {
UInt64 written = 0;
for (UInt32 i = 0; format[i] != '\0'; i++) {
if (format[i] == '%') {
i++;
if (format[i] == '\0') break;
switch (format[i]) {
case 's': {
const char* vaArgString = va_arg(args, const char*);
if (!vaArgString) vaArgString = "(null)";
while (*vaArgString) sConsoleBufferAdd(string, size, &written, *vaArgString++);
break;
}
case 'c': {
char character = (char)va_arg(args, int);
sConsoleBufferAdd(string, size, &written, character);
break;
}
case 'd': {
Int64 number = va_arg(args, int);
if (number < 0) {
sConsoleBufferAdd(string, size, &written, '-');
number = -number;
}
UInt64 unsignedNumber = (UInt64)number;
char tempBuffer[32];
Int32 position = 0;
if (unsignedNumber == 0) tempBuffer[position++] = '0';
while (unsignedNumber > 0) {
tempBuffer[position++] = (unsignedNumber % 10) + '0';
unsignedNumber /= 10;
}
while (position > 0) sConsoleBufferAdd(string, size, &written, tempBuffer[--position]);
break;
}
case 'x':
case 'X': {
UInt64 unsignedNumber = va_arg(args, unsigned long long);
UInt8 padding = (format[i] == 'X') ? 16 : 0;
char tempBuffer[32];
int position = 0;
const char* hex = "0123456789ABCDEF";
if (unsignedNumber == 0 && padding == 0) tempBuffer[position++] = '0';
while (unsignedNumber > 0) {
tempBuffer[position++] = hex[unsignedNumber % 16];
unsignedNumber /= 16;
}
while (position < padding) tempBuffer[position++] = '0';
while (position > 0) sConsoleBufferAdd(string, size, &written, tempBuffer[--position]);
break;
}
case '%': {
sConsoleBufferAdd(string, size, &written, '%');
break;
}
default: {
sConsoleBufferAdd(string, size, &written, '%');
sConsoleBufferAdd(string, size, &written, format[i]);
break;
}
}
} else {
sConsoleBufferAdd(string, size, &written, format[i]);
}
}
if (size > 0) {
if (written < size) string[written] = '\0';
else string[size - 1] = '\0';
}
return (int)written;
}
Int32 StringFormat(char* destination, usize size, const char* format, ...) {
va_list args;
va_start(args, format);
int returnValue = sStringFormatVariadic(destination, size, format, args);
va_end(args);
return returnValue;
}
Int32 ConsolePrint(const char *format, ...) {
char buffer[kConsoleDefaultBufferSize];
va_list args;
va_start(args, format);
int length = sStringFormatVariadic(buffer, sizeof(buffer), format, args);
va_end(args);
UInt64 writeLength = ((UInt64)length < sizeof(buffer)) ? length : (sizeof(buffer) - 1);
OSServiceIOWrite(1, buffer, writeLength);
return (int)writeLength;
}
Int32 ConsoleGetCharacter() {
char character;
UInt64 serviceCallResult = OSServiceIORead(0, &character, 1);
if (serviceCallResult <= 0) return kConsoleEOF;
return (int)(unsigned char)character;
}
char* ConsoleReadLine(char* string, UInt64 size) {
if (size == 0) return string;
UInt64 i = 0;
int character;
while (i < size - 1) {
character = ConsoleGetCharacter();
if (character == kConsoleEOF || character == '\n' || character == '\r') break;
if (character == '\b') {
if (i > 0) {
i--;
ConsolePrint("\b \b");
}
continue;
}
string[i++] = (char)character;
sConsoleWriteCharacter(character);
}
string[i] = '\0';
sConsoleWriteCharacter('\n');
return string;
}
+104
View File
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
// brutally copypasting from kernel/mm/heap.c
#include <Memory.h>
#include <String.h>
static MemoryBlockHeader* sMemoryHeapListHead = nullptr;
extern UInt64 OSServiceMemoryAllocate(UInt64 size);
static void sMemoryCombineForward(MemoryBlockHeader* current) {
if (!current->next || !current->next->isFree) return;
current->size += sizeof(MemoryBlockHeader) + current->next->size;
current->next = current->next->next;
if (current->next) current->next->previous = current;
}
void* MemoryAllocate(UInt64 size) {
if (size == 0) return nullptr;
UInt64 alignedSize = (size + (kMemoryAlignment-1)) & ~(kMemoryAlignment - 1);
MemoryBlockHeader* current = sMemoryHeapListHead;
MemoryBlockHeader* lastBlock = nullptr;
while (current) {
if (current->isFree && current->size >= alignedSize) {
if (current->size > alignedSize + sizeof(MemoryBlockHeader) + kMemoryAlignment) {
MemoryBlockHeader* newBlock = (MemoryBlockHeader*)((UInt64)current + sizeof(MemoryBlockHeader) + alignedSize);
newBlock->size = current->size - alignedSize - sizeof(MemoryBlockHeader);
newBlock->isFree = true;
newBlock->next = current->next;
newBlock->previous = current;
newBlock->magic = kMemoryBlockMagic;
if (current->next) current->next->previous = newBlock;
current->next = newBlock;
current->size = alignedSize;
}
current->isFree = false;
return (void*)((UInt64)current + sizeof(MemoryBlockHeader));
}
lastBlock = current;
current = current->next;
}
UInt64 sizeNeededToAllocate = alignedSize + sizeof(MemoryBlockHeader);
UInt64 pageAlignedSize = (sizeNeededToAllocate + (kMemoryPageSize-1)) & ~(kMemoryPageSize-1);
UInt64 newMemoryAddress = OSServiceMemoryAllocate(pageAlignedSize);
if (newMemoryAddress == 0) return nullptr;
MemoryBlockHeader* newBlock = (MemoryBlockHeader*)newMemoryAddress;
newBlock->size = pageAlignedSize - sizeof(MemoryBlockHeader);
newBlock->isFree = true;
newBlock->magic = kMemoryBlockMagic;
newBlock->next = nullptr;
newBlock->previous = lastBlock;
if (lastBlock) {
lastBlock->next = newBlock;
} else {
sMemoryHeapListHead = newBlock;
}
return MemoryAllocate(size);
}
void MemoryFree(void* pointer) {
if (!pointer) return;
MemoryBlockHeader* current = (MemoryBlockHeader*)((UInt64)pointer - sizeof(MemoryBlockHeader));
if (current->magic != kMemoryBlockMagic) return;
current->isFree = true;
if (current->next && current->next->isFree) sMemoryCombineForward(current);
if (current->previous && current->previous->isFree) sMemoryCombineForward(current->previous);
}
void* MemoryReallocate(void* pointer, UInt64 newSize) {
if (!pointer) return MemoryAllocate(newSize);
if (newSize == 0) {
MemoryFree(pointer);
return nullptr;
}
MemoryBlockHeader* current = (MemoryBlockHeader*)((UInt64)pointer - sizeof(MemoryBlockHeader));
if (current->size >= newSize) return pointer;
if (current->next &&
current->next->isFree &&
(current->size + sizeof(MemoryBlockHeader) + current->next->size) >= newSize) {
sMemoryCombineForward(current);
return pointer;
}
void* newPointer = MemoryAllocate(newSize);
if (!newPointer) return nullptr;
MemoryCopy(newPointer, pointer, current->size);
MemoryFree(pointer);
return newPointer;
}
+43
View File
@@ -0,0 +1,43 @@
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright (c) 2026 0xKarinyash
bits 64
section .text
global OSServiceProcessExit
global OSServiceProcessSpawn
global OSServiceMemoryAllocate
global OSServiceIOWrite
global OSServiceIORead
global OSServiceProcessWait
OSServiceProcessExit:
mov rax, 0
syscall
ret
OSServiceProcessSpawn:
mov rax, 1
syscall
ret
OSServiceMemoryAllocate:
mov rax, 2
syscall
ret
OSServiceIOWrite:
mov rax, 3
syscall
ret
OSServiceIORead:
mov rax, 4
syscall
ret
OSServiceProcessWait:
mov rax, 5
syscall
ret
+15
View File
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <Process.h>
extern Int32 OSServiceProcessSpawn(const char* path);
extern Int32 OSServiceProcessWait(UInt64 pid);
Int32 ProcessSpawn(const char* path) {
return OSServiceProcessSpawn(path);
}
Int32 ProcessWait(UInt64 pid) {
return OSServiceProcessWait(pid);
}
+14
View File
@@ -0,0 +1,14 @@
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright (c) 2026 0xKarinyash
[bits 64]
section .text
global _start
extern main
extern OSServiceProcessExit
_start:
call main
mov rdi, rax
call OSServiceProcessExit
+126
View File
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <String.h>
static char* olds;
void* MemorySet(void* destination, UInt8 value, UInt64 count) {
UInt8* bytePointer = (UInt8*) destination;
while (count--) {
*bytePointer++ = (UInt8)value;
}
return destination;
}
void* MemoryCopy(void* destination, const void* source, UInt64 count) {
UInt8* destinationBuffer = (UInt8*)destination;
const UInt8* sourceBuffer = (const UInt8*)source;
while (count >= 8) {
*(UInt64*)destinationBuffer = *(const UInt64*)sourceBuffer;
destinationBuffer += 8;
sourceBuffer += 8;
count -= 8;
}
while (count > 0) {
*destinationBuffer++ = *sourceBuffer++;
count--;
}
return destination;
}
Int32 StringCompare(const char* firstString, const char* secondString) {
while (*firstString && (*firstString == *secondString)) {
firstString++;
secondString++;
}
return *(const unsigned char*)firstString - *(const unsigned char*)secondString;
}
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit) {
while (limit > 0) {
if (*firstString != *secondString) return *(unsigned char*)firstString - *(unsigned char*)secondString;
if (*firstString == '\0') return 0;
firstString++;
secondString++;
limit--;
}
return 0;
}
char* StringCopy(char* destination, const char* source) {
char* saved = destination;
while (*source) *destination++ = *source++;
*destination = 0;
return saved;
}
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit) {
char* saved = destination;
while (*source && limit > 0) {
*destination++ = *source++;
limit--;
}
while (limit > 0) {
*destination++ = 0;
limit--;
}
return saved;
}
UInt64 StringGetLength(const char* string) {
UInt64 result = 0;
for (result = 0; string[result]; result++);
return result;
}
static inline int sStringIsInSet(char character, const char* set) {
while (*set) {
if (*set == character) return 1;
set++;
}
return 0;
}
UInt64 StringGetInitialSpan(const char* string, const char* characterSet) {
UInt64 count = 0;
while (*string && sStringIsInSet(*string, characterSet)) {
count++;
string++;
}
return count;
}
char* StringFindFirstCharacterFromSet(const char* string, const char* set) {
while (*string) {
if (sStringIsInSet(*string, set)) {
return (char*)string;
}
string++;
}
return nullptr;
}
// took from https://github.com/walac/glibc/blob/master/string/strtok.c
char* StringTokenize(char* string, const char* delimiters) {
char* token;
if (string == nullptr) string = olds;
string += StringGetInitialSpan(string, delimiters);
if (*string == '\0') {
olds = string;
return nullptr;
}
token = string;
string = StringFindFirstCharacterFromSet(token, delimiters);
if (string == nullptr) olds = token + StringGetLength(token);
else {
*string = '\0';
olds = string + 1;
}
return token;
}
+9
View File
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.20)
project(termOSh LANGUAGES C)
file(GLOB_RECURSE TERMOSH_SOURCES "src/*.c")
add_termos_executable(termosh "${TERMOSH_SOURCES}")
target_include_directories(termosh PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/inc"
)
+7
View File
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
void not_implemented_yet();
void cmd_spawn(const char* path);
+9
View File
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
#include "tokens.h"
termosh_token char2token(char* token);
int tokenize(char* buffer, char* tokens[], int max_tokens);
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#pragma once
typedef enum {
TOKEN_EMPTY,
TOKEN_NULL,
TOKEN_ILLEGAL,
TOKEN_QUIT,
TOKEN_CLEAR,
TOKEN_HELP,
TOKEN_SPAWN,
} termosh_token;
+5
View File
@@ -0,0 +1,5 @@
#include <termOS.h>
void not_implemented_yet() {
ConsolePrint("Not implemented yet!\n");
}
+16
View File
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include "handlers.h"
#include <termOS.h>
void cmd_spawn(const char* path) {
Int32 pid = ProcessSpawn(path);
if (pid < 0) {
switch (pid) {
case -1: ConsolePrint("\"%s\" not found.\n", path); break;
default: ConsolePrint("failed to spawn (%d)\n", pid); break;
}
} else {
ProcessWait(pid);
}
}
+31
View File
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <termOS.h>
#include "parser.h"
#include "handlers.h"
#define BUFFER_SIZE 512
int main() {
while (true) {
ConsolePrint("termosh_> ");
char cmdbuff[BUFFER_SIZE];
ConsoleReadLine(cmdbuff, BUFFER_SIZE);
char* tokens[BUFFER_SIZE];
int tokens_count = tokenize(cmdbuff, tokens, BUFFER_SIZE);
if (tokens_count < 1) continue;
termosh_token token = char2token(tokens[0]);
switch (token) {
case TOKEN_QUIT: return 0;
case TOKEN_CLEAR: not_implemented_yet(); break;
case TOKEN_HELP: not_implemented_yet(); break;
case TOKEN_SPAWN: if (tokens_count >= 2) cmd_spawn(tokens[1]); break;
default: {
char buff[256];
StringFormat(buff, sizeof(buff), "/System/CoreServices/%s", tokens[0]);
cmd_spawn(buff);
}
}
}
}
+49
View File
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (c) 2026 0xKarinyash
#include <termOS.h>
#include "parser.h"
#include "tokens.h"
static const char* delim = " \t\r\n";
typedef struct {
char* str;
termosh_token token;
} termosh_token_map;
static const termosh_token_map token_map[] = {
{"q", TOKEN_QUIT},
{"quit", TOKEN_QUIT},
{"exit", TOKEN_QUIT},
{"clear", TOKEN_CLEAR},
{"help", TOKEN_HELP},
{"spawn", TOKEN_SPAWN},
{nullptr, TOKEN_NULL}
};
termosh_token char2token(char* token) {
for (int i = 0; token_map[i].str != nullptr; i++) {
if (StringCompare(token, token_map[i].str) == 0) {
return token_map[i].token;
}
}
return TOKEN_ILLEGAL;
}
int tokenize(char* buffer, char* tokens[], int max_tokens) {
char* token = StringTokenize(buffer, delim);
int i = 0;
while (token != nullptr && i < max_tokens) {
tokens[i] = token;
token = StringTokenize(nullptr, delim);
i++;
}
return i;
}