feat: Symmetric Multiprocessing, text editor improvements, merge doom libc, implement math functions
This commit is contained in:
+10
-6
@@ -59,7 +59,7 @@ BINDIR := bin
|
||||
PROGRAMS := $(notdir $(wildcard src/*))
|
||||
|
||||
# Programs with custom Makefiles (built separately).
|
||||
CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth desktop login shell rpgdemo paint tcc screenshot
|
||||
CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth desktop login shell rpgdemo paint tcc screenshot texteditor
|
||||
SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS))
|
||||
|
||||
# Build targets: system programs go to bin/os/, apps go to bin/apps/<name>/.
|
||||
@@ -81,9 +81,9 @@ CA_CERTS := $(BINDIR)/etc/ca-certificates.crt
|
||||
# Common shared assets (wallpapers, etc.)
|
||||
COMMONKEEP := $(BINDIR)/common/.keep
|
||||
|
||||
.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth login desktop shell rpgdemo paint tcc screenshot icons fonts bearssl libc tls libjpeg libjpegwrite install-apps
|
||||
.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth login desktop shell rpgdemo paint tcc screenshot texteditor icons fonts bearssl libc tls libjpeg libjpegwrite install-apps
|
||||
|
||||
all: bearssl libc libjpeg libjpegwrite tls $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth doom rpgdemo paint tcc screenshot login desktop shell icons fonts install-apps $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP)
|
||||
all: bearssl libc libjpeg libjpegwrite tls $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth doom rpgdemo paint tcc screenshot texteditor login desktop shell icons fonts install-apps $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP)
|
||||
|
||||
# Build BearSSL static library (cross-compiled for freestanding x86_64).
|
||||
BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc)
|
||||
@@ -192,12 +192,16 @@ fonts:
|
||||
paint: libc
|
||||
$(MAKE) -C src/paint
|
||||
|
||||
# Build text editor standalone GUI app (depends on libc).
|
||||
texteditor: libc
|
||||
$(MAKE) -C src/texteditor
|
||||
|
||||
# Build RPG demo game via its own Makefile (depends on libc).
|
||||
rpgdemo: libc
|
||||
$(MAKE) -C src/rpgdemo
|
||||
|
||||
# Build doom via its own Makefile.
|
||||
doom:
|
||||
# Build doom via its own Makefile (depends on libc).
|
||||
doom: libc
|
||||
$(MAKE) -C src/doom
|
||||
|
||||
# Build screenshot tool (depends on libc and libjpegwrite).
|
||||
@@ -214,7 +218,7 @@ tcc: libc
|
||||
cp include/libc/sys/*.h $(BINDIR)/lib/tcc/include/sys/
|
||||
|
||||
# Install app bundles (manifests, icons, data files) into bin/apps/<name>/.
|
||||
install-apps: doom rpgdemo paint spreadsheet weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer volume music bluetooth screenshot
|
||||
install-apps: doom rpgdemo paint spreadsheet weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer volume music bluetooth screenshot texteditor
|
||||
../scripts/install_apps.sh
|
||||
|
||||
# Copy man pages into bin/man/ so mkramdisk.sh picks them up.
|
||||
|
||||
@@ -17,13 +17,24 @@ double ceil(double x);
|
||||
double sqrt(double x);
|
||||
double sin(double x);
|
||||
double cos(double x);
|
||||
double tan(double x);
|
||||
double atan(double x);
|
||||
double atan2(double y, double x);
|
||||
double pow(double base, double exp);
|
||||
double log(double x);
|
||||
double log2(double x);
|
||||
double log10(double x);
|
||||
double exp(double x);
|
||||
double fmod(double x, double y);
|
||||
double round(double x);
|
||||
|
||||
float floorf(float x);
|
||||
float ceilf(float x);
|
||||
float fabsf(float x);
|
||||
float sqrtf(float x);
|
||||
float sinf(float x);
|
||||
float cosf(float x);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,8 @@ int write(int fd, const void *buf, size_t count);
|
||||
int close(int fd);
|
||||
long lseek(int fd, long offset, int whence);
|
||||
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -36,10 +36,8 @@ CFLAGS := \
|
||||
-fdata-sections \
|
||||
-m64 \
|
||||
-march=x86-64 \
|
||||
-mno-80387 \
|
||||
-mno-mmx \
|
||||
-mno-sse \
|
||||
-mno-sse2 \
|
||||
-msse \
|
||||
-msse2 \
|
||||
-mno-red-zone \
|
||||
-mcmodel=small \
|
||||
-isystem $(LIBC_INC) \
|
||||
|
||||
+279
-13
@@ -11,6 +11,7 @@
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -626,7 +627,18 @@ char *getenv(const char *name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void (*_atexit_funcs[32])(void);
|
||||
static int _atexit_count = 0;
|
||||
|
||||
int atexit(void (*func)(void)) {
|
||||
if (_atexit_count >= 32 || func == NULL) return -1;
|
||||
_atexit_funcs[_atexit_count++] = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exit(int status) {
|
||||
for (int i = _atexit_count - 1; i >= 0; i--)
|
||||
_atexit_funcs[i]();
|
||||
_zos_syscall1(SYS_EXIT, (long)status);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -1439,19 +1451,6 @@ int fstat(int fd, struct stat *buf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
stdlib.h: system() and atexit()
|
||||
======================================================================== */
|
||||
|
||||
static void (*_atexit_funcs[32])(void);
|
||||
static int _atexit_count = 0;
|
||||
|
||||
int atexit(void (*func)(void)) {
|
||||
if (_atexit_count >= 32 || func == NULL) return -1;
|
||||
_atexit_funcs[_atexit_count++] = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
stdlib.h: qsort
|
||||
======================================================================== */
|
||||
@@ -1520,3 +1519,270 @@ ldiv_t ldiv(long numer, long denom) {
|
||||
long atol(const char *s) {
|
||||
return strtol(s, NULL, 10);
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
math.h functions
|
||||
======================================================================== */
|
||||
|
||||
/* Constants */
|
||||
#define M_PI 3.14159265358979323846
|
||||
#define M_PI_2 1.57079632679489661923
|
||||
#define M_LN2 0.69314718055994530942
|
||||
#define M_LOG2E 1.44269504088896340736
|
||||
|
||||
double fabs(double x) { return x < 0 ? -x : x; }
|
||||
|
||||
double floor(double x) {
|
||||
double t = (double)(long long)x;
|
||||
return (x < t) ? t - 1.0 : t;
|
||||
}
|
||||
|
||||
double ceil(double x) {
|
||||
double f = floor(x);
|
||||
return (x > f) ? f + 1.0 : f;
|
||||
}
|
||||
|
||||
double fmod(double x, double y) {
|
||||
if (y == 0.0) return 0.0;
|
||||
return x - (double)((long long)(x / y)) * y;
|
||||
}
|
||||
|
||||
double sqrt(double x) {
|
||||
if (x <= 0.0) return 0.0;
|
||||
double guess = x;
|
||||
for (int i = 0; i < 20; i++)
|
||||
guess = (guess + x / guess) * 0.5;
|
||||
return guess;
|
||||
}
|
||||
|
||||
/* ---- sin / cos via range reduction + minimax polynomial ---- */
|
||||
|
||||
/* Reduce x to [-pi, pi] */
|
||||
static double _reduce_angle(double x) {
|
||||
/* Bring into [-2pi, 2pi] via fmod, then into [-pi, pi] */
|
||||
x = fmod(x, 2.0 * M_PI);
|
||||
if (x > M_PI) x -= 2.0 * M_PI;
|
||||
else if (x < -M_PI) x += 2.0 * M_PI;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Core sin approximation for x in [-pi/2, pi/2].
|
||||
Taylor series to degree 17 for < 1e-11 accuracy at the boundary. */
|
||||
static double _sin_core(double x) {
|
||||
double x2 = x * x;
|
||||
return x * (1.0 + x2 * (-1.0/6.0 + x2 * (1.0/120.0 + x2 * (-1.0/5040.0
|
||||
+ x2 * (1.0/362880.0 + x2 * (-1.0/39916800.0
|
||||
+ x2 * (1.0/6227020800.0 + x2 * (-1.0/1307674368000.0))))))));
|
||||
}
|
||||
|
||||
double sin(double x) {
|
||||
x = _reduce_angle(x);
|
||||
/* Reduce to [-pi/2, pi/2] using sin(pi - x) = sin(x) */
|
||||
if (x > M_PI_2) x = M_PI - x;
|
||||
else if (x < -M_PI_2) x = -M_PI - x;
|
||||
return _sin_core(x);
|
||||
}
|
||||
|
||||
double cos(double x) {
|
||||
return sin(x + M_PI_2);
|
||||
}
|
||||
|
||||
/* ---- log via exponent extraction + polynomial on [1, 2) ---- */
|
||||
|
||||
/* Union for double bit manipulation */
|
||||
typedef union { double d; uint64_t u; } _dbl_bits;
|
||||
|
||||
double log(double x) {
|
||||
if (x <= 0.0) return -HUGE_VAL;
|
||||
if (x == 1.0) return 0.0;
|
||||
|
||||
/* Extract exponent and mantissa: x = m * 2^e, where m in [1, 2) */
|
||||
_dbl_bits bits;
|
||||
bits.d = x;
|
||||
int e = (int)((bits.u >> 52) & 0x7FF) - 1023;
|
||||
bits.u = (bits.u & 0x000FFFFFFFFFFFFFULL) | 0x3FF0000000000000ULL;
|
||||
double m = bits.d;
|
||||
|
||||
/* log(x) = e * ln(2) + log(m), where m in [1, 2)
|
||||
Use log(m) = log((1+f)/(1-f)) = 2*(f + f^3/3 + f^5/5 + ...) where f = (m-1)/(m+1) */
|
||||
double f = (m - 1.0) / (m + 1.0);
|
||||
double f2 = f * f;
|
||||
double ln_m = 2.0 * f * (1.0 + f2 * (1.0/3.0 + f2 * (1.0/5.0 + f2 * (1.0/7.0
|
||||
+ f2 * (1.0/9.0 + f2 * (1.0/11.0 + f2 * (1.0/13.0
|
||||
+ f2 * (1.0/15.0 + f2 * (1.0/17.0)))))))));
|
||||
|
||||
return (double)e * M_LN2 + ln_m;
|
||||
}
|
||||
|
||||
/* ---- exp via range reduction to [0, ln2) + polynomial ---- */
|
||||
|
||||
double exp(double x) {
|
||||
if (x == 0.0) return 1.0;
|
||||
if (x < -708.0) return 0.0;
|
||||
if (x > 709.0) return HUGE_VAL;
|
||||
|
||||
/* Range reduction: exp(x) = 2^k * exp(r), where x = k*ln(2) + r, |r| <= ln(2)/2 */
|
||||
double k_real = floor(x * M_LOG2E + 0.5);
|
||||
int k = (int)k_real;
|
||||
double r = x - k_real * M_LN2;
|
||||
|
||||
/* Pade-like polynomial for exp(r), |r| <= ~0.347:
|
||||
1 + r + r^2/2 + r^3/6 + r^4/24 + r^5/120 + r^6/720 + r^7/5040 */
|
||||
double exp_r = 1.0 + r * (1.0 + r * (1.0/2.0 + r * (1.0/6.0
|
||||
+ r * (1.0/24.0 + r * (1.0/120.0 + r * (1.0/720.0 + r * (1.0/5040.0)))))));
|
||||
|
||||
/* Multiply by 2^k via bit manipulation */
|
||||
_dbl_bits bits;
|
||||
bits.d = exp_r;
|
||||
bits.u += (uint64_t)k << 52;
|
||||
return bits.d;
|
||||
}
|
||||
|
||||
/* ---- pow via exp(exp * log(base)) ---- */
|
||||
|
||||
double pow(double base, double e) {
|
||||
if (e == 0.0) return 1.0;
|
||||
if (base == 0.0) return 0.0;
|
||||
if (base == 1.0) return 1.0;
|
||||
if (e == 1.0) return base;
|
||||
|
||||
/* Integer exponent fast path */
|
||||
if (e == (double)(long long)e && fabs(e) < 64) {
|
||||
long long ei = (long long)e;
|
||||
int neg = 0;
|
||||
if (ei < 0) { neg = 1; ei = -ei; }
|
||||
double r = 1.0;
|
||||
double b = base;
|
||||
while (ei > 0) {
|
||||
if (ei & 1) r *= b;
|
||||
b *= b;
|
||||
ei >>= 1;
|
||||
}
|
||||
return neg ? 1.0 / r : r;
|
||||
}
|
||||
|
||||
/* General case */
|
||||
if (base < 0.0) return 0.0; /* negative base with fractional exp is undefined (in reals) */
|
||||
return exp(e * log(base));
|
||||
}
|
||||
|
||||
double tan(double x) {
|
||||
double c = cos(x);
|
||||
if (c == 0.0) return (sin(x) > 0.0) ? HUGE_VAL : -HUGE_VAL;
|
||||
return sin(x) / c;
|
||||
}
|
||||
|
||||
double log2(double x) { return log(x) * M_LOG2E; }
|
||||
double log10(double x) { return log(x) * 0.43429448190325182765; /* 1/ln(10) */ }
|
||||
|
||||
/* ---- atan / atan2 via polynomial approximation ---- */
|
||||
|
||||
/* Core atan for |x| <= ~0.414 (= tan(pi/8)).
|
||||
Taylor series converges well in this small range. */
|
||||
static double _atan_small(double x) {
|
||||
double x2 = x * x;
|
||||
return x * (1.0 + x2 * (-1.0/3.0 + x2 * (1.0/5.0 + x2 * (-1.0/7.0
|
||||
+ x2 * (1.0/9.0 + x2 * (-1.0/11.0 + x2 * (1.0/13.0
|
||||
+ x2 * (-1.0/15.0 + x2 * (1.0/17.0)))))))));
|
||||
}
|
||||
|
||||
#define M_PI_4 0.78539816339744830962
|
||||
|
||||
/* atan for x >= 0, using range reduction:
|
||||
- |x| <= tan(pi/8) ~ 0.4142: polynomial directly
|
||||
- 0.4142 < |x| <= 1: atan(x) = pi/4 + atan((x-1)/(x+1))
|
||||
- |x| > 1: atan(x) = pi/2 - atan(1/x) */
|
||||
static double _atan_positive(double x) {
|
||||
if (x <= 0.41421356237309504) {
|
||||
return _atan_small(x);
|
||||
} else if (x <= 1.0) {
|
||||
return M_PI_4 + _atan_small((x - 1.0) / (x + 1.0));
|
||||
} else {
|
||||
return M_PI_2 - _atan_positive(1.0 / x);
|
||||
}
|
||||
}
|
||||
|
||||
double atan2(double y, double x) {
|
||||
if (x == 0.0 && y == 0.0) return 0.0;
|
||||
if (x == 0.0) return (y > 0.0) ? M_PI_2 : -M_PI_2;
|
||||
if (y == 0.0) return (x > 0.0) ? 0.0 : M_PI;
|
||||
|
||||
double a = _atan_positive(fabs(y) / fabs(x));
|
||||
|
||||
/* Map to correct quadrant */
|
||||
if (x < 0.0) a = M_PI - a;
|
||||
if (y < 0.0) a = -a;
|
||||
return a;
|
||||
}
|
||||
|
||||
double atan(double x) {
|
||||
if (x >= 0.0) return _atan_positive(x);
|
||||
return -_atan_positive(-x);
|
||||
}
|
||||
|
||||
double round(double x) { return floor(x + 0.5); }
|
||||
|
||||
/* ---- atof: basic floating-point string parser ---- */
|
||||
|
||||
double atof(const char *s) {
|
||||
if (s == NULL) return 0.0;
|
||||
|
||||
while (isspace((unsigned char)*s)) s++;
|
||||
|
||||
int neg = 0;
|
||||
if (*s == '-') { neg = 1; s++; }
|
||||
else if (*s == '+') s++;
|
||||
|
||||
/* Integer part */
|
||||
double val = 0.0;
|
||||
while (isdigit((unsigned char)*s)) {
|
||||
val = val * 10.0 + (*s - '0');
|
||||
s++;
|
||||
}
|
||||
|
||||
/* Fractional part */
|
||||
if (*s == '.') {
|
||||
s++;
|
||||
double place = 0.1;
|
||||
while (isdigit((unsigned char)*s)) {
|
||||
val += (*s - '0') * place;
|
||||
place *= 0.1;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Exponent part */
|
||||
if (*s == 'e' || *s == 'E') {
|
||||
s++;
|
||||
int eneg = 0;
|
||||
if (*s == '-') { eneg = 1; s++; }
|
||||
else if (*s == '+') s++;
|
||||
int ev = 0;
|
||||
while (isdigit((unsigned char)*s)) {
|
||||
ev = ev * 10 + (*s - '0');
|
||||
s++;
|
||||
}
|
||||
double mul = 1.0;
|
||||
while (ev-- > 0) mul *= 10.0;
|
||||
if (eneg) val /= mul;
|
||||
else val *= mul;
|
||||
}
|
||||
|
||||
return neg ? -val : val;
|
||||
}
|
||||
|
||||
float floorf(float x) { return (float)floor((double)x); }
|
||||
float ceilf(float x) { return (float)ceil((double)x); }
|
||||
float fabsf(float x) { return x < 0.0f ? -x : x; }
|
||||
float sqrtf(float x) { return (float)sqrt((double)x); }
|
||||
float sinf(float x) { return (float)sin((double)x); }
|
||||
float cosf(float x) { return (float)cos((double)x); }
|
||||
|
||||
/* ========================================================================
|
||||
unistd.h: sleep
|
||||
======================================================================== */
|
||||
|
||||
unsigned int sleep(unsigned int seconds) {
|
||||
(void)seconds;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1076,8 +1076,8 @@ static void filemanager_open_entry(FileManagerState* fm, int idx) {
|
||||
montauk::spawn("0:/apps/music/music.elf", fullpath);
|
||||
} else if (str_ends_with(fm->entry_names[idx], ".elf")) {
|
||||
montauk::spawn(fullpath);
|
||||
} else if (fm->desktop) {
|
||||
open_texteditor_with_file(fm->desktop, fullpath);
|
||||
} else {
|
||||
montauk::spawn("0:/apps/texteditor/texteditor.elf", fullpath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@ endif
|
||||
DOOM_SRC := ../../../doomgeneric/doomgeneric
|
||||
LIBC_INC := ../../include/libc
|
||||
PROG_INC := ../../include
|
||||
LIBDIR := ../../lib
|
||||
LINK_LD := ../../link.ld
|
||||
BINDIR := ../../bin
|
||||
OBJDIR := obj
|
||||
@@ -153,7 +154,7 @@ DOOM_SRCS := \
|
||||
z_zone.c
|
||||
|
||||
# Local source files
|
||||
LOCAL_SRCS := doomgeneric_montauk.c libc.c
|
||||
LOCAL_SRCS := doomgeneric_montauk.c
|
||||
|
||||
# ---- Object files ----
|
||||
|
||||
@@ -171,7 +172,7 @@ all: $(TARGET)
|
||||
|
||||
$(TARGET): $(ALL_OBJS) $(LINK_LD) Makefile
|
||||
mkdir -p $(BINDIR)/apps/doom
|
||||
$(LD) $(CFLAGS) $(LDFLAGS) $(ALL_OBJS) -o $@
|
||||
$(LD) $(CFLAGS) $(LDFLAGS) $(ALL_OBJS) $(LIBDIR)/libc/liblibc.a -o $@
|
||||
|
||||
# DOOM source files (from doomgeneric directory)
|
||||
$(OBJDIR)/%.o: $(DOOM_SRC)/%.c Makefile
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
# Makefile for texteditor (standalone Window Server app) on MontaukOS
|
||||
# Copyright (c) 2026 Daniel Hammer
|
||||
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
# ---- Toolchain ----
|
||||
|
||||
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf-
|
||||
ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
|
||||
CXX := $(TOOLCHAIN_PREFIX)g++
|
||||
else
|
||||
CXX := g++
|
||||
endif
|
||||
|
||||
# ---- Paths ----
|
||||
|
||||
PROG_INC := ../../include
|
||||
LINK_LD := ../../link.ld
|
||||
BINDIR := ../../bin
|
||||
OBJDIR := obj
|
||||
LIBDIR := ../../lib
|
||||
|
||||
# ---- Compiler flags ----
|
||||
|
||||
CXXFLAGS := \
|
||||
-std=gnu++20 \
|
||||
-g -O2 -pipe \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-unused-function \
|
||||
-nostdinc \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-check \
|
||||
-fno-PIC \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-m64 \
|
||||
-march=x86-64 \
|
||||
-msse \
|
||||
-msse2 \
|
||||
-mno-red-zone \
|
||||
-mcmodel=small \
|
||||
-I $(PROG_INC) \
|
||||
-isystem $(PROG_INC)/libc \
|
||||
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
|
||||
-isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include
|
||||
|
||||
# ---- Linker flags ----
|
||||
|
||||
LDFLAGS := \
|
||||
-nostdlib \
|
||||
-static \
|
||||
-Wl,--build-id=none \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,-m,elf_x86_64 \
|
||||
-z max-page-size=0x1000 \
|
||||
-T $(LINK_LD)
|
||||
|
||||
# ---- Source files ----
|
||||
|
||||
SRCS := main.cpp stb_truetype_impl.cpp
|
||||
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
|
||||
|
||||
# ---- Target ----
|
||||
|
||||
TARGET := $(BINDIR)/apps/texteditor/texteditor.elf
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS) $(LINK_LD) Makefile
|
||||
mkdir -p $(BINDIR)/apps/texteditor
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp Makefile
|
||||
mkdir -p $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* stb_truetype_impl.cpp
|
||||
* Single compilation unit for stb_truetype in MontaukOS freestanding environment
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <montauk/heap.h>
|
||||
#include <montauk/string.h>
|
||||
#include <gui/stb_math.h>
|
||||
|
||||
// Override all stb_truetype dependencies before including the implementation
|
||||
|
||||
#define STBTT_ifloor(x) ((int) stb_floor(x))
|
||||
#define STBTT_iceil(x) ((int) stb_ceil(x))
|
||||
#define STBTT_sqrt(x) stb_sqrt(x)
|
||||
#define STBTT_pow(x,y) stb_pow(x,y)
|
||||
#define STBTT_fmod(x,y) stb_fmod(x,y)
|
||||
#define STBTT_cos(x) stb_cos(x)
|
||||
#define STBTT_acos(x) stb_acos(x)
|
||||
#define STBTT_fabs(x) stb_fabs(x)
|
||||
|
||||
#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x))
|
||||
#define STBTT_free(x,u) ((void)(u), montauk::mfree(x))
|
||||
|
||||
#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n)
|
||||
#define STBTT_memset(d,v,n) montauk::memset(d,v,n)
|
||||
|
||||
#define STBTT_strlen(x) montauk::slen(x)
|
||||
|
||||
#define STBTT_assert(x) ((void)(x))
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <gui/stb_truetype.h>
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* syntax_highlight.hpp
|
||||
* C syntax highlighting for the MontaukOS text editor
|
||||
* Activated for .c and .h files
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gui/gui.hpp>
|
||||
|
||||
using namespace gui;
|
||||
|
||||
// ============================================================================
|
||||
// Token types
|
||||
// ============================================================================
|
||||
|
||||
enum SynToken : uint8_t {
|
||||
SYN_NORMAL,
|
||||
SYN_KEYWORD,
|
||||
SYN_TYPE,
|
||||
SYN_PREPROCESSOR,
|
||||
SYN_STRING,
|
||||
SYN_CHAR,
|
||||
SYN_COMMENT,
|
||||
SYN_NUMBER,
|
||||
SYN_OPERATOR,
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Colors for each token type
|
||||
// ============================================================================
|
||||
|
||||
inline Color syn_color(SynToken tok) {
|
||||
switch (tok) {
|
||||
case SYN_KEYWORD: return Color::from_rgb(0xC5, 0x62, 0x8C); // magenta-pink
|
||||
case SYN_TYPE: return Color::from_rgb(0x2E, 0x86, 0xAB); // teal
|
||||
case SYN_PREPROCESSOR: return Color::from_rgb(0x8B, 0x6E, 0xB5); // purple
|
||||
case SYN_STRING: return Color::from_rgb(0x6A, 0x9F, 0x3A); // green
|
||||
case SYN_CHAR: return Color::from_rgb(0x6A, 0x9F, 0x3A); // green
|
||||
case SYN_COMMENT: return Color::from_rgb(0x7A, 0x7A, 0x7A); // gray
|
||||
case SYN_NUMBER: return Color::from_rgb(0xC9, 0x7E, 0x2A); // orange
|
||||
case SYN_OPERATOR: return Color::from_rgb(0x40, 0x40, 0x40); // dark gray
|
||||
default: return Color::from_rgb(0x1E, 0x1E, 0x1E); // near-black
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Keyword / type lookup
|
||||
// ============================================================================
|
||||
|
||||
inline bool syn_is_alpha(char c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||
}
|
||||
|
||||
inline bool syn_is_alnum(char c) {
|
||||
return syn_is_alpha(c) || (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
inline bool syn_is_digit(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
inline bool syn_is_hex(char c) {
|
||||
return syn_is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
inline bool syn_streq(const char* buf, int len, const char* kw) {
|
||||
int i = 0;
|
||||
while (i < len && kw[i]) {
|
||||
if (buf[i] != kw[i]) return false;
|
||||
i++;
|
||||
}
|
||||
return i == len && kw[i] == '\0';
|
||||
}
|
||||
|
||||
inline SynToken syn_classify_word(const char* buf, int len) {
|
||||
// C keywords
|
||||
static const char* keywords[] = {
|
||||
"auto", "break", "case", "const", "continue", "default", "do",
|
||||
"else", "enum", "extern", "for", "goto", "if", "inline",
|
||||
"register", "restrict", "return", "sizeof", "static", "struct",
|
||||
"switch", "typedef", "union", "volatile", "while",
|
||||
"NULL", "true", "false", "nullptr",
|
||||
};
|
||||
// C types
|
||||
static const char* types[] = {
|
||||
"void", "char", "short", "int", "long", "float", "double",
|
||||
"signed", "unsigned", "bool", "_Bool",
|
||||
"int8_t", "int16_t", "int32_t", "int64_t",
|
||||
"uint8_t", "uint16_t", "uint32_t", "uint64_t",
|
||||
"size_t", "ssize_t", "ptrdiff_t", "intptr_t", "uintptr_t",
|
||||
"FILE",
|
||||
};
|
||||
|
||||
for (int i = 0; i < (int)(sizeof(keywords) / sizeof(keywords[0])); i++) {
|
||||
if (syn_streq(buf, len, keywords[i])) return SYN_KEYWORD;
|
||||
}
|
||||
for (int i = 0; i < (int)(sizeof(types) / sizeof(types[0])); i++) {
|
||||
if (syn_streq(buf, len, types[i])) return SYN_TYPE;
|
||||
}
|
||||
return SYN_NORMAL;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Per-line highlighter
|
||||
// ============================================================================
|
||||
//
|
||||
// Fills `out[]` with SynToken values for each character in the line.
|
||||
// `in_block_comment` is the multi-line comment state carried across lines:
|
||||
// - pass in the state from the previous line
|
||||
// - on return, updated for the next line
|
||||
//
|
||||
// `line` points to the first char of the line, `len` is its length
|
||||
// (excluding the newline). `out` must have room for `len` entries.
|
||||
|
||||
inline void syn_highlight_line(const char* line, int len, SynToken* out, bool& in_block_comment) {
|
||||
int i = 0;
|
||||
|
||||
while (i < len) {
|
||||
// ---- Block comment continuation ----
|
||||
if (in_block_comment) {
|
||||
while (i < len) {
|
||||
if (i + 1 < len && line[i] == '*' && line[i + 1] == '/') {
|
||||
out[i] = SYN_COMMENT;
|
||||
out[i + 1] = SYN_COMMENT;
|
||||
i += 2;
|
||||
in_block_comment = false;
|
||||
break;
|
||||
}
|
||||
out[i] = SYN_COMMENT;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
char c = line[i];
|
||||
|
||||
// ---- Line comment ----
|
||||
if (c == '/' && i + 1 < len && line[i + 1] == '/') {
|
||||
while (i < len) out[i++] = SYN_COMMENT;
|
||||
break;
|
||||
}
|
||||
|
||||
// ---- Block comment start ----
|
||||
if (c == '/' && i + 1 < len && line[i + 1] == '*') {
|
||||
in_block_comment = true;
|
||||
out[i] = SYN_COMMENT;
|
||||
out[i + 1] = SYN_COMMENT;
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Preprocessor directive ----
|
||||
if (c == '#') {
|
||||
// Check that only whitespace precedes the #
|
||||
bool is_pp = true;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (line[j] != ' ' && line[j] != '\t') { is_pp = false; break; }
|
||||
}
|
||||
if (is_pp) {
|
||||
while (i < len) {
|
||||
// Handle line-comment inside preprocessor
|
||||
if (i + 1 < len && line[i] == '/' && line[i + 1] == '/') {
|
||||
while (i < len) out[i++] = SYN_COMMENT;
|
||||
break;
|
||||
}
|
||||
// Handle block comment start inside preprocessor
|
||||
if (i + 1 < len && line[i] == '/' && line[i + 1] == '*') {
|
||||
in_block_comment = true;
|
||||
out[i] = SYN_COMMENT;
|
||||
out[i + 1] = SYN_COMMENT;
|
||||
i += 2;
|
||||
// Continue consuming as comment
|
||||
while (i < len) {
|
||||
if (i + 1 < len && line[i] == '*' && line[i + 1] == '/') {
|
||||
out[i] = SYN_COMMENT;
|
||||
out[i + 1] = SYN_COMMENT;
|
||||
i += 2;
|
||||
in_block_comment = false;
|
||||
break;
|
||||
}
|
||||
out[i] = SYN_COMMENT;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
out[i] = SYN_PREPROCESSOR;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- String literal ----
|
||||
if (c == '"') {
|
||||
out[i++] = SYN_STRING;
|
||||
while (i < len) {
|
||||
if (line[i] == '\\' && i + 1 < len) {
|
||||
out[i] = SYN_STRING;
|
||||
out[i + 1] = SYN_STRING;
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
if (line[i] == '"') {
|
||||
out[i++] = SYN_STRING;
|
||||
break;
|
||||
}
|
||||
out[i++] = SYN_STRING;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Character literal ----
|
||||
if (c == '\'') {
|
||||
out[i++] = SYN_CHAR;
|
||||
while (i < len) {
|
||||
if (line[i] == '\\' && i + 1 < len) {
|
||||
out[i] = SYN_CHAR;
|
||||
out[i + 1] = SYN_CHAR;
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
if (line[i] == '\'') {
|
||||
out[i++] = SYN_CHAR;
|
||||
break;
|
||||
}
|
||||
out[i++] = SYN_CHAR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Numbers ----
|
||||
if (syn_is_digit(c) || (c == '.' && i + 1 < len && syn_is_digit(line[i + 1]))) {
|
||||
// Hex
|
||||
if (c == '0' && i + 1 < len && (line[i + 1] == 'x' || line[i + 1] == 'X')) {
|
||||
out[i] = SYN_NUMBER; out[i + 1] = SYN_NUMBER;
|
||||
i += 2;
|
||||
while (i < len && syn_is_hex(line[i])) out[i++] = SYN_NUMBER;
|
||||
} else {
|
||||
// Decimal / float
|
||||
while (i < len && (syn_is_digit(line[i]) || line[i] == '.'))
|
||||
out[i++] = SYN_NUMBER;
|
||||
}
|
||||
// Suffixes: u, l, f, etc.
|
||||
while (i < len && (line[i] == 'u' || line[i] == 'U' ||
|
||||
line[i] == 'l' || line[i] == 'L' ||
|
||||
line[i] == 'f' || line[i] == 'F'))
|
||||
out[i++] = SYN_NUMBER;
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Identifiers / keywords / types ----
|
||||
if (syn_is_alpha(c)) {
|
||||
int start = i;
|
||||
while (i < len && syn_is_alnum(line[i])) i++;
|
||||
SynToken tok = syn_classify_word(line + start, i - start);
|
||||
for (int j = start; j < i; j++) out[j] = tok;
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Operators ----
|
||||
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '%' ||
|
||||
c == '=' || c == '!' || c == '<' || c == '>' || c == '&' ||
|
||||
c == '|' || c == '^' || c == '~' || c == '?' || c == ':') {
|
||||
out[i++] = SYN_OPERATOR;
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Everything else (whitespace, braces, parens, etc.) ----
|
||||
out[i++] = SYN_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Extension check
|
||||
// ============================================================================
|
||||
|
||||
inline bool syn_is_c_file(const char* filepath) {
|
||||
if (!filepath || filepath[0] == '\0') return false;
|
||||
int len = 0;
|
||||
while (filepath[len]) len++;
|
||||
if (len >= 2 && filepath[len - 2] == '.' &&
|
||||
(filepath[len - 1] == 'c' || filepath[len - 1] == 'h'))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user