diff --git a/.gitignore b/.gitignore index fe51ca2c..421c5399 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,8 @@ fs/Bin/Chess.nse fs/Tests/*.png fs/User/* +crt2/build/* +crt2/lib/* crt/build_libnanoshell crt/build_crt1 crt/crt1.o diff --git a/apps/CommonMakefile b/apps/CommonMakefile index 4c2dbeb2..30225ed5 100644 --- a/apps/CommonMakefile +++ b/apps/CommonMakefile @@ -14,8 +14,10 @@ LD=ld AS=nasm STRIP=strip +USERLDFLAGS ?= + CFLAGS=-I $(INC_DIR) -I $(LII_DIR) -ffreestanding -target i686-elf -O2 -fno-exceptions -Wall -Wextra -std=c99 -mno-sse2 $(USERCFLAGS) -LDFLAGS=-T link.ld -g -nostdlib -zmax-page-size=0x1000 +LDFLAGS=-T link.ld -g -nostdlib -zmax-page-size=0x1000 $(USERLDFLAGS) ASFLAGS=-f elf32 # Compile the application @@ -58,7 +60,7 @@ endif $(APP_TARGET): $(APP_O_FILES) $(LIB_O_FILES) $(RESOURCE_COMP_OBJ) @echo "linking: $@" @echo $(APP_O_FILES) $(LIB_O_FILES) $(RESOURCE_COMP_OBJ) - @$(LD) $(LDFLAGS) -o $@ $^ $(LGCC) + $(LD) $(LDFLAGS) -o $@ $^ $(LGCC) # Build Library $(BLD_DIR)/%.asm.o: $(LIS_DIR)/%.asm diff --git a/apps/List/Makefile b/apps/List/Makefile index 236bb47a..929697b5 100644 --- a/apps/List/Makefile +++ b/apps/List/Makefile @@ -5,4 +5,76 @@ SRC_DIR=src APP_C_FILES=$(shell find $(SRC_DIR) -type f -name '*.c') APP_S_FILES=$(shell find $(SRC_DIR) -type f -name '*.asm') -include ../CommonMakefile +USERLDFLAGS = -L ../../crt2/lib -lnanoshell -lcrts --dynamic-linker nanoshelllinker + +# NanoShell Operating System + +# Common Makefile. This is supposed to be included by built in applications, and not spawned by itself.. + +INC_DIR=include +BLD_DIR=build +LIS_DIR=../../crt/src +LII_DIR=../../crt/include + +LGCC=../../tools/libgcc-i686.a + +CC=clang +LD=ld +AS=nasm +STRIP=strip + +USERLDFLAGS ?= + +CFLAGS=-I $(INC_DIR) -I $(LII_DIR) -ffreestanding -target i686-elf -O2 -fno-exceptions -Wall -Wextra -std=c99 -mno-sse2 $(USERCFLAGS) +LDFLAGS=-T link.ld -g -nostdlib -zmax-page-size=0x1000 $(USERLDFLAGS) +ASFLAGS=-f elf32 + +# Compile the application +APP_TARGET=$(APPLICATION_NAME).nse + +APP_O_FILES=$(patsubst $(SRC_DIR)/%,$(BLD_DIR)/%.o,$(APP_C_FILES) $(APP_S_FILES)) + +all: application + +clean: + rm -rf $(BLD_DIR)/* + rm -f $(APP_TARGET) + +application: $(APP_TARGET) + +# Build Resource File + +RC = ../../tools/rc + +RESOURCE=resource.rc +RESOURCE_COMPILED=$(BLD_DIR)/rescomp.asm +RESOURCE_COMP_OBJ=$(BLD_DIR)/rescomp.o + +ifeq ("$(wildcard $(RESOURCE))", "") +RESOURCE_COMP_OBJ := +else +$(RESOURCE_COMP_OBJ): $(RESOURCE_COMPILED) + @mkdir -p $(dir $@) + @echo "assembling resource file" + @$(AS) $(ASFLAGS) -o $@ $^ + +$(RESOURCE_COMPILED): $(RESOURCE) + @mkdir -p $(dir $@) + @$(RC) $< $@ /S +endif + +$(APP_TARGET): $(APP_O_FILES) $(RESOURCE_COMP_OBJ) + @echo "linking: $@" + @echo $(APP_O_FILES) $(RESOURCE_COMP_OBJ) + $(LD) $(LDFLAGS) -o $@ $^ $(LGCC) + +# Build Source +$(BLD_DIR)/%.asm.o: $(SRC_DIR)/%.asm + @mkdir -p $(dir $@) + @echo "assembling: $<" + @$(AS) $(ASFLAGS) -o $@ $^ + +$(BLD_DIR)/%.c.o: $(SRC_DIR)/%.c + @mkdir -p $(dir $@) + @echo "compiling: $<" + @$(CC) $(CFLAGS) -c $< -o $@ diff --git a/crt/lib/crt1.o b/crt/lib/crt1.o index bc581516..d9401c2c 100644 Binary files a/crt/lib/crt1.o and b/crt/lib/crt1.o differ diff --git a/crt/lib/crti.o b/crt/lib/crti.o index 6addee9f..1edeb881 100644 Binary files a/crt/lib/crti.o and b/crt/lib/crti.o differ diff --git a/crt/lib/crtn.o b/crt/lib/crtn.o index 6addee9f..1edeb881 100644 Binary files a/crt/lib/crtn.o and b/crt/lib/crtn.o differ diff --git a/crt/lib/libnanoshell.a b/crt/lib/libnanoshell.a index 7cdfcb98..2fb2340d 100644 Binary files a/crt/lib/libnanoshell.a and b/crt/lib/libnanoshell.a differ diff --git a/crt/src/a_assert.c b/crt/src/a_assert.c index b8754d89..1a52480b 100644 --- a/crt/src/a_assert.c +++ b/crt/src/a_assert.c @@ -11,10 +11,18 @@ #include "crtlib.h" #include "crtinternal.h" +__attribute__((noreturn)) +void abort() +{ + // TODO + *((uint32_t*)0xFFFFFFF4) = 0xFFFFFFFF; + while (true); +} + void OnAssertionFail(const char *cond_msg, const char *file, int line) { LogMsg("ASSERTION FAILED!"); LogMsg("The assertion \"%s\" failed at %s:%d.", cond_msg, file, line); LogMsg("The program will now exit."); - exit(1); + abort(); } diff --git a/crt/src/entry.c b/crt/src/entry.c index 20cff68a..f09fa960 100644 --- a/crt/src/entry.c +++ b/crt/src/entry.c @@ -11,13 +11,6 @@ #include "crtlib.h" #include "crtinternal.h" -__attribute__((noreturn)) -void abort() -{ - *((uint32_t*)0xFFFFFFF4) = 0xFFFFFFFF; - while (true); -} - __attribute__((noreturn)) void exit (int number); int main(int argc, char** argv); diff --git a/crt2/Makefile b/crt2/Makefile new file mode 100644 index 00000000..444ee60a --- /dev/null +++ b/crt2/Makefile @@ -0,0 +1,96 @@ +# crt2/Makefile +# Copyright (C) 2023 iProgramInCpp +# Makefile for the NanoShell C Runtime Library + +CC = clang +LD = ld +AS = nasm +AR = ar + +# Description: +# libnanoshell - The shared library that implements most of nanoshell's libc. +# libnanoentry - The static library that implements the entry point of all programs. + +# Note: Libnanoshell also includes libgcc. + +# Objects included with libnanoshell. +LIBN_C_FILES = \ + src/a_assert.c \ + src/a_cc.c \ + src/a_env.c \ + src/a_error.c \ + src/a_file.c \ + src/a_math.c \ + src/a_mem.c \ + src/a_printf.c \ + src/a_sort.c \ + src/a_string.c \ + src/a_time.c \ + src/a_ver.c \ + src/a_video.c \ + src/a_window.c \ + src/calls.c +LIBN_ASM_FILES = \ + src/math.asm + +# Objects included with libnanoentry. +LIBE_C_FILES = \ + src/entry.c +LIBE_ASM_FILES = \ + src/crt0.asm + +CRT_STUB = src/zstub.c + +LGCC=../tools/libgcc-i686.a + +LIBN_O_FILES = $(patsubst src/%,build/libnanoshell/%.o,$(LIBN_C_FILES) $(LIBN_ASM_FILES)) +LIBE_O_FILES = $(patsubst src/%,build/libnanoentry/%.o,$(LIBE_C_FILES) $(LIBE_ASM_FILES)) + +CFLAGS=-I include/ -I src/ -ffreestanding -target i686-elf -g -fno-exceptions -Wall -Wextra -std=c99 -mno-sse -mno-sse2 -fpic +ASFLAGS=-f elf32 +ARFLAGS=rcs + +LIBN_TARGET = lib/libnanoshell.so +LIBE_TARGET = lib/libnanoentry.a + +all: libnanoshell libnanoentry + +clean: + rm -rf build + rm -rf lib + +# Build LibNanoshell +libnanoshell: $(LIBN_O_FILES) + @mkdir -p $(dir $@) + @echo "[LibNanoShell] Linking" + @mkdir -p $(dir $(LIBN_TARGET)) + @$(LD) -shared -T lib_i386.ld -g -nostdlib -zmax-page-size=0x1000 -o $(LIBN_TARGET) $(LIBN_O_FILES) $(LGCC) + +# Build LibNanoentry +libnanoentry: $(LIBE_O_FILES) + @mkdir -p $(dir $@) + @echo "[LibNanoEntry] Archiving" + @$(AR) $(ARFLAGS) $(LIBE_TARGET) $^ + +# Build LibNanoshell object files +build/libnanoshell/%.asm.o: src/%.asm + @mkdir -p $(dir $@) + @echo "[LibNanoShell] Assembling $<" + @$(AS) $(ASFLAGS) -o $@ $^ + +build/libnanoshell/%.c.o: src/%.c + @mkdir -p $(dir $@) + @echo "[LibNanoShell] Compiling $<" + @$(CC) $(CFLAGS) -c $< -o $@ + +# Build Libnanoentry object files. +build/libnanoentry/%.c.o: src/%.c + @mkdir -p $(dir $@) + @echo "[LibNanoEntry] Compiling $<" + @$(CC) $(CFLAGS) -c $< -o $@ + +build/libnanoentry/%.asm.o: src/%.asm + @mkdir -p $(dir $@) + @echo "[LibNanoEntry] Assembling $<" + @$(AS) $(ASFLAGS) -o $@ $^ + diff --git a/crt2/README.md b/crt2/README.md new file mode 100644 index 00000000..716f11ee --- /dev/null +++ b/crt2/README.md @@ -0,0 +1,31 @@ +### The NanoShell C Standard Library + +#### File structure + +The `include` directory contains include headers. Make +sure to use the `-nostdinc` switch when compiling an +application. + +The `src` directory contains all NanoShell C Standard +Library code. Please note that new files must be added +manually to the Makefile in the directory this README +resides in. + +The provided makefile has a couple functions: + +`make all`: Compiles the crti.o and crtn.o stubs, the +crt1.o entry point, and the libnanoshell.a archive for +the contents of the NanoShell C library. + +`make update`: Does the same as `male all` and copies +the libraries into system root +(`git repo root/fs/User/Library`). + +`make updinc`: Updates the include files from `crt/` +to `git repo root/fs/User/Include`. + +**Note**: The `User/` directory is entirely optional +and not at all used by NanoShell itself. It's required +to use TCC, though, a port of which is provided within +`apps/Tcc`. It is NanoShell's counterpart to the `usr` +directory. diff --git a/crt2/crt1.ld b/crt2/crt1.ld new file mode 100644 index 00000000..f3f3fee5 --- /dev/null +++ b/crt2/crt1.ld @@ -0,0 +1,7 @@ +/** + * This linker script is purely to let the linker know + * that we're trying to get an elf32-i386 object out of + * crt1. + */ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) \ No newline at end of file diff --git a/crt2/include/LICENSE.md b/crt2/include/LICENSE.md new file mode 100644 index 00000000..09c59c30 --- /dev/null +++ b/crt2/include/LICENSE.md @@ -0,0 +1,8 @@ +Copyright 2022 mintsuki and contributors. + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/crt2/include/README b/crt2/include/README new file mode 100644 index 00000000..fc0a0a4c --- /dev/null +++ b/crt2/include/README @@ -0,0 +1,5 @@ +Source: https://github.com/mintsuki/freestanding-headers/tree/74f400838200f0b2968241155302cd1261e22b5f + +This is a collection of freestanding C headers, for use with GCC or Clang. + + diff --git a/crt2/include/alloca.h b/crt2/include/alloca.h new file mode 100644 index 00000000..53d02c1d --- /dev/null +++ b/crt2/include/alloca.h @@ -0,0 +1,9 @@ +// alloca.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _ALLOCA__H +#define _ALLOCA__H + +#define alloca __builtin_alloca + +#endif//_ALLOCA__H diff --git a/crt2/include/assert.h b/crt2/include/assert.h new file mode 100644 index 00000000..5d61264c --- /dev/null +++ b/crt2/include/assert.h @@ -0,0 +1,17 @@ +// assert.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _ASSERT__H +#define _ASSERT__H + +void OnAssertionFail(const char *cond_msg, const char *file, int line); +#define assert(cond) do { if (!(cond)) OnAssertionFail(#cond, __FILE__, __LINE__); } while (0) +#define ASSERT assert + +#ifdef STATIC_ASSERT +#undef STATIC_ASSERT +#endif + +#define STATIC_ASSERT _Static_assert + +#endif//_ASSERT__H diff --git a/crt2/include/ctype.h b/crt2/include/ctype.h new file mode 100644 index 00000000..1ecb88a1 --- /dev/null +++ b/crt2/include/ctype.h @@ -0,0 +1,25 @@ +// ctype.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _CTYPE__H +#define _CTYPE__H + +// Character classification +int isalnum(int c); +int isalpha(int c); +int isascii(int c); +int isblank(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); + +// Character space mapping functions +int toupper(int c); +int tolower(int c); + +#endif//_CTYPE__H diff --git a/crt2/include/dirent.h b/crt2/include/dirent.h new file mode 100644 index 00000000..a7e821d6 --- /dev/null +++ b/crt2/include/dirent.h @@ -0,0 +1,30 @@ +// dirent.h +// Copyright (C) 2023 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _DIRENT_H +#define _DIRENT_H + +#include + +// NanoShell specifics that have yet to have POSIX names assigned to them. (TODO) +int FiOpenDir (const char* pFileName); +int FiCloseDir (int dd); +int FiReadDir (DirEnt* pDirEnt, int dd); +int FiSeekDir (int dd, int loc); +int FiRewindDir(int dd); +int FiTellDir (int dd); +int FiStatAt (int dd, const char*pfn, StatResult* pres); +int FiStat (const char*pfn, StatResult* pres); +int FiChDir (const char*pfn); +const char* FiGetCwd(); +const char* ErrNoStr(int errno); + +// Standard C functions +DIR* opendir(const char* dirname); +int closedir(DIR *dirp); +void rewinddir(DIR* dirp); +int telldir(DIR* dirp); +void seekdir(DIR* dirp, int told); +struct dirent* readdir(DIR *dirp); + +#endif//_DIRENT_H \ No newline at end of file diff --git a/crt2/include/errno.h b/crt2/include/errno.h new file mode 100644 index 00000000..b57efde6 --- /dev/null +++ b/crt2/include/errno.h @@ -0,0 +1,16 @@ +// errno.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __ERRNO_H +#define __ERRNO_H + +#include + +int seterrno(int en); +int geterrno(int en); +int* geterrnoptr(); +#define errno (*geterrnoptr()) + +void perror(const char* fmt, ...); + +#endif//__ERRNO_H \ No newline at end of file diff --git a/crt2/include/fcntl.h b/crt2/include/fcntl.h new file mode 100644 index 00000000..afa943ef --- /dev/null +++ b/crt2/include/fcntl.h @@ -0,0 +1,9 @@ +// fcntl.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __FCNTL_H +#define __FCNTL_H + +//TODO + +#endif//__FCNTL_H \ No newline at end of file diff --git a/crt2/include/inttypes.h b/crt2/include/inttypes.h new file mode 100644 index 00000000..4851957c --- /dev/null +++ b/crt2/include/inttypes.h @@ -0,0 +1,10 @@ +// inttypes.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __INTTYPES_H +#define __INTTYPES_H + +#include +typedef signed long ssize_t; + +#endif//__INTTYPES_H \ No newline at end of file diff --git a/crt2/include/iso646.h b/crt2/include/iso646.h new file mode 100644 index 00000000..599705ee --- /dev/null +++ b/crt2/include/iso646.h @@ -0,0 +1,16 @@ +#ifndef _ISO646_H +#define _ISO646_H 1 + +#define and && +#define and_eq &= +#define bitand & +#define bitor | +#define compl ~ +#define not ! +#define not_eq != +#define or || +#define or_eq |= +#define xor ^ +#define xor_eq ^= + +#endif diff --git a/crt2/include/limits.h b/crt2/include/limits.h new file mode 100644 index 00000000..e80f3f2a --- /dev/null +++ b/crt2/include/limits.h @@ -0,0 +1,26 @@ +// limits.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __LIMITS__H +#define __LIMITS__H + +#define CHAR_BIT (8) +#define SCHAR_MIN (-128) +#define SCHAR_MAX (127) +#define UCHAR_MAX (255) +#define CHAR_MIN (-128) +#define CHAR_MAX (127) +#define SHRT_MIN (-32768) +#define SHRT_MAX (32767) +#define USHRT_MAX (65535) +#define INT_MIN (-2147483648) +#define INT_MAX (2147483647) +#define UINT_MAX (4294967295U) +#define LONG_MIN INT_MIN +#define LONG_MAX INT_MAX +#define ULONG_MAX UINT_MAX +#define LLONG_MIN (-9223372036854775808LL) +#define LLONG_MAX (9223372036854775807LL) +#define ULLONG_MAX (18446744073709551615ULL) + +#endif//__LIMITS__H \ No newline at end of file diff --git a/crt2/include/math.h b/crt2/include/math.h new file mode 100644 index 00000000..a1d2e708 --- /dev/null +++ b/crt2/include/math.h @@ -0,0 +1,9 @@ +// math.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __MATH_H +#define __MATH_H + +//TODO + +#endif//__MATH_H \ No newline at end of file diff --git a/crt2/include/nanoshell/dirent_types.h b/crt2/include/nanoshell/dirent_types.h new file mode 100644 index 00000000..690b77d2 --- /dev/null +++ b/crt2/include/nanoshell/dirent_types.h @@ -0,0 +1,44 @@ +// nanoshell/dirent_types.h +// Copyright (C) 2023 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _DIRENT_TYPES_H +#define _DIRENT_TYPES_H + +// matches the FILE_TYPE enum (unistd_types.h) +#define DT_UNKNOWN (0) +#define DT_REG (1) +#define DT_CHR (2) +#define DT_BLK (3) +#define DT_FIFO (4) +#define DT_LNK (5) +#define DT_DIR (8) +#define DT_SOCK (32) // fantasy value. Will never be set unless we implement unix sockets. + +typedef struct DirEntS +{ + char m_name[128]; //+nullterm, so 127 concrete chars + uint32_t m_inode; //device specific + uint32_t m_type; +} +DirEnt; + +struct dirent +{ + ino_t d_ino; // Inode number + off_t d_off; // Offset in the file (i.e. the value of telldir() for this dirent) + uint16_t d_reclen; // Record length + uint8_t d_type; // Optional type of file, may be DT_UNKNOWN if not supported. + char d_name[128]; // Null terminated file name. The size matches that of the DirEnt structure's +}; + +typedef struct dirent dirent; + +typedef struct +{ + int m_DirHandle; + DirEnt m_NDirEnt; // nanoshell dirent + dirent m_PDirEnt; // posix dirent +} +DIR; // pointer to a DIR returned by opendir + +#endif//_DIRENT_TYPES_H \ No newline at end of file diff --git a/crt2/include/nanoshell/error_nums.h b/crt2/include/nanoshell/error_nums.h new file mode 100644 index 00000000..6c24556c --- /dev/null +++ b/crt2/include/nanoshell/error_nums.h @@ -0,0 +1,45 @@ +// nanoshell/error_nums.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __NANOSHELL_ERROR_NUMS_H +#define __NANOSHELL_ERROR_NUMS_H + +// use with the negative prefix +enum +{ + ENOTHING, // No Error + EACCES, // Permission denied + EEXIST, // File exists + EINTR, // Interrupted system call + EINVAL, // Invalid argument + EIO, // I/O error + EISDIR, // Is a directory + ELOOP, // Too many symbolic links + EMFILE, // Too many open files + ENAMETOOLONG, // File or path name too long + ENFILE, // Too many open files in system + ENOENT, // No such file or directory + ENOSR, // Out of stream resources + ENOSPC, // No space left on device + ENOTDIR, // Not a directory + ENXIO, // No such device or address + EOVERFLOW, // Value too large for defined data type + EROFS, // Read only file system + EAGAIN, // No more processes + ENOMEM, // Not enough memory + ETXTBUSY, // Text file busy + EBADF, // Bad file descriptor + ESPIPE, // Illegal seek + EIEIO, // Computer bought the farm + ENOTSUP, // Operation not supported + EXDEV, // Cross device operation not supported + EBUSY, // Resource is busy + ENOTEMPTY, // Directory is not empty + ENOTTY, // Invalid input/output control request + ERANGE, // Range error + EDOM, // Domain error + ECOUNT, +}; + + +#endif//__NANOSHELL_ERROR_NUMS_H diff --git a/crt2/include/nanoshell/graphics.h b/crt2/include/nanoshell/graphics.h new file mode 100644 index 00000000..4185a0b5 --- /dev/null +++ b/crt2/include/nanoshell/graphics.h @@ -0,0 +1,45 @@ +// nanoshell/graphics.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _NANOSHELL_GRAPHICS__H +#define _NANOSHELL_GRAPHICS__H + +#include + +int GetScreenSizeX(); +int GetScreenSizeY(); +int GetWidth(Rectangle* rect); +int GetHeight(Rectangle* rect); +void VidPlotPixel(unsigned x, unsigned y, unsigned color); +void VidFillScreen(unsigned color); +void VidDrawVLine(unsigned color, int top, int bottom, int x); +void VidDrawHLine(unsigned color, int left, int right, int y); +void VidDrawLine(unsigned p, int x1, int y1, int x2, int y2); +void VidSetFont(unsigned fontType); +void VidPlotChar (char c, unsigned ox, unsigned oy, unsigned colorFg, unsigned colorBg /*=0xFFFFFFFF*/); +void VidBlitImage(Image* pImage, int x, int y); +void VidBlitImageResize(Image* pImage, int x, int y, int w, int h); +void VidTextOut(const char* pText, unsigned ox, unsigned oy, unsigned colorFg, unsigned colorBg /*=0xFFFFFFFF*/); +void VidTextOutInternal(const char* pText, unsigned ox, unsigned oy, unsigned colorFg, unsigned colorBg, bool doNotActuallyDraw, int* widthx, int* heightx); +void VidDrawText(const char* pText, Rectangle rect, unsigned drawFlags, unsigned colorFg, unsigned colorBg); +void VidShiftScreen (int amount); +void VidFillRect(unsigned color, int left, int top, int right, int bottom); +void VidDrawRect(unsigned color, int left, int top, int right, int bottom); +void VidFillRectangle(unsigned color, Rectangle rect); +void VidFillRectHGradient(unsigned colorL, unsigned colorR, int left, int top, int right, int bottom); +void VidFillRectVGradient(unsigned colorU, unsigned colorD, int left, int top, int right, int bottom); +void VidDrawRectangle(unsigned color, Rectangle rect); +void SetMousePos (int pX, int pY); +void RenderIcon(int type, int x, int y); +void RenderIconOutline(int type, int x, int y, uint32_t color); +void RenderIconForceSize(int type, int x, int y, int size); +void RenderIconForceSizeOutline(int type, int x, int y, int size, uint32_t color); + +bool RectangleContains(Rectangle *r, Point *p); +bool RectangleOverlap (Rectangle *r1, Rectangle *r2); + +unsigned VidReadPixel(unsigned x, unsigned y); + +VBEData* VidSetVbeData (VBEData* pData); + +#endif//_NANOSHELL_GRAPHICS__H diff --git a/crt2/include/nanoshell/graphics_types.h b/crt2/include/nanoshell/graphics_types.h new file mode 100644 index 00000000..9b4e462f --- /dev/null +++ b/crt2/include/nanoshell/graphics_types.h @@ -0,0 +1,329 @@ +// nanoshell/graphics_types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _NANOSHELL_GRAPHICS_TYPES_H +#define _NANOSHELL_GRAPHICS_TYPES_H + +#define TRANSPARENT 0xFFFFFFFF + +#define FLAGS_TOO(flags, color) (flags | (color & 0XFFFFFF)) + +#define TEXT_RENDER_TRANSPARENT 0xFFFFFFFF +#define TEXT_RENDER_BOLD 0x01000000 + +#define RECT(rect,x,y,w,h) do {\ + rect.left = x, rect.top = y, rect.right = x+w, rect.bottom = y+h;\ +} while (0) + +typedef struct +{ + int left, top, right, bottom; +} +Rectangle; + +typedef struct +{ + int x, y; +} +Point; + +typedef struct +{ + short width, height; + const uint32_t *framebuffer; +} +Image; + +enum +{ + ICON_NULL, + ICON_CABINET, + ICON_CHIP, + ICON_CHIP_SQ, + ICON_COMPUTER, + ICON_COMPUTER_SHUTDOWN, + ICON_DESKTOP, + ICON_DRAW, + ICON_EARTH, + ICON_ERROR, + ICON_EXECUTE_FILE, + ICON_FILE, + ICON_FILES, + ICON_FOLDER, + ICON_FOLDER_BLANK, + ICON_FOLDER_MOVE, + ICON_FOLDER_PARENT, + ICON_FOLDER16_CLOSED, + ICON_FOLDER16_OPEN, + ICON_GLOBE, + ICON_GO, + ICON_HAND, + ICON_HELP, + ICON_INFO, + ICON_KEYBOARD, + ICON_KEYBOARD2, + ICON_LAPTOP, + ICON_NOTES, + ICON_PAINT, + ICON_SERIAL, + ICON_STOP, + ICON_TEXT_FILE, + ICON_WARNING, + ICON_NANOSHELL_LETTERS, + ICON_NANOSHELL_LETTERS16, + ICON_NANOSHELL, + ICON_NANOSHELL16, + ICON_BOMB, + ICON_BOMB_SPIKEY, + ICON_FILE16, + ICON_TEXT_FILE16, + ICON_EXECUTE_FILE16, + ICON_FOLDER_PARENT16, + //icons V1.1 + ICON_FOLDER_SETTINGS, + ICON_CABINET16, + ICON_COMPUTER16, + ICON_COMMAND, + ICON_COMMAND16, + ICON_ERROR16, + //icons V1.2 + ICON_LOCK, + ICON_DIRECTIONS, + ICON_CERTIFICATE, + ICON_FILE_WRITE, + ICON_SCRAP_FILE, + ICON_SCRAP_FILE16, + ICON_RESMON, + ICON_BILLBOARD, + ICON_FILE_CSCRIPT, + ICON_FILE_CSCRIPT16, + ICON_FILE_CLICK, + ICON_KEYS, + ICON_RESTRICTED, + ICON_HOME, + ICON_HOME16, + ICON_ADAPTER, + ICON_CLOCK, + ICON_CLOCK16, + //icons V1.3 + ICON_APPLICATION, + ICON_APPLICATION16, + ICON_TASKBAR, + ICON_APP_DEMO, + ICON_COMPUTER_FLAT, + ICON_CALCULATOR, + ICON_CALCULATOR16, + ICON_DESKTOP2, + ICON_MOUSE, + //Icons V1.31 + ICON_AMBULANCE, + //icons V1.32 + ICON_FONTS, + ICON_FONTS16, + //icons V1.33 + ICON_RESMON16, + ICON_NOTES16, + ICON_FILE_NANO, + //icons V1.34 + ICON_CLOCK_EMPTY,//Special case which draws more stuff + //icons V1.35 + ICON_RUN, + ICON_RUN16, + //icons V1.4 + ICON_DEVTOOL, + ICON_DEVTOOL_FILE, + ICON_HEX_EDIT, + ICON_CHAIN, + ICON_CHAIN16, + ICON_DEVTOOL16, + ICON_TODO, + ICON_FOLDER_DOCU, + ICON_DLGEDIT, + ICON_DESK_SETTINGS, + ICON_SHUTDOWN, + ICON_NOTEPAD, + ICON_FILE_MKDOWN, + ICON_FILE_MKDOWN16, + ICON_COMPUTER_PANIC, + ICON_EXPERIMENT, + ICON_GRAPH, + ICON_CABINET_COMBINE, + ICON_REMOTE, + ICON_CABINET_OLD, + //icons V1.5 + ICON_DEVICE_CHAR, + ICON_DEVICE_BLOCK, + ICON_HARD_DRIVE, + ICON_HARD_DRIVE_MOUNT, + ICON_WINDOW, + ICON_WINDOW_SNAP, + ICON_WINDOW_OVERLAP, + ICON_SWEEP_SMILE, + ICON_SWEEP_CLICK, + ICON_SWEEP_DEAD, + ICON_SWEEP_CARET, + ICON_DLGEDIT16, + ICON_BOMB_SPIKEY16, + ICON_MAGNIFY, + ICON_MAGNIFY16, + ICON_TAR_ARCHIVE, + ICON_SYSMON, + ICON_SYSMON16, + ICON_COMPUTER_SHUTDOWN16, + ICON_EXIT, + ICON_KEY, + ICON_KEYB_REP_SPEED, + ICON_KEYB_REP_DELAY, + ICON_MONITOR, + //icons V1.6 + ICON_FILE_INI, + ICON_WMENU, + ICON_WMENU16, + ICON_FILE_IMAGE, + ICON_FILE_IMAGE16, + ICON_FILE_LOG, + ICON_STICKY_NOTES, + ICON_STICKY_NOTES16, + ICON_NOTE_YELLOW, + ICON_NOTE_BLUE, + ICON_NOTE_GREEN, + ICON_NOTE_WHITE, + ICON_FOLDER_OPEN, + //icons V1.61 + ICON_EXPERIMENT2, + ICON_FLOPPY, ICON_ACTION_SAVE = ICON_FLOPPY, + ICON_ACTION_SAVE16, + ICON_ACTION_OPEN, + ICON_ACTION_OPEN16, + ICON_PLUS, + //icons V1.7 + ICON_PASTE, + ICON_PASTE16, + ICON_DELETE, + ICON_DELETE16, + ICON_COPY, + ICON_COPY16, + ICON_BACK, + ICON_BACK16, + ICON_FORWARD, + ICON_FORWARD16, + ICON_UNDO, + ICON_UNDO16, + ICON_REDO, + ICON_REDO16, + ICON_FILE_SEARCH, + ICON_FILE_SEARCH16, + ICON_FILE_PROPERTIES, + ICON_FILE_PROPERTIES16, + ICON_PROPERTIES, + ICON_PROPERTIES16, + ICON_WHATS_THIS, + ICON_WHATS_THIS16, + ICON_VIEW_ICON, + ICON_VIEW_ICON16, + ICON_VIEW_LIST, + ICON_VIEW_LIST16, + ICON_VIEW_TABLE, + ICON_VIEW_TABLE16, + ICON_SORT_ALPHA, + ICON_SORT_ALPHA16, + ICON_FORM, + ICON_FORM16, + ICON_JOURNAL, + ICON_JOURNAL16, + ICON_PACKAGER, + ICON_PACKAGER16, + //icons V1.71 + ICON_BOX_CHECK, + ICON_BOX_UNCHECK, + ICON_FOLDER_SETTINGS16, + //icons V1.8 + ICON_MINIMIZE, + ICON_MAXIMIZE, + ICON_RESTORE, + ICON_CLOSE, + ICON_ARROW_UP, + ICON_ARROW_DOWN, + ICON_ARROW_LEFT, + ICON_ARROW_RIGHT, + ICON_PIPE, + ICON_PIPE16, + ICON_VB_CURSOR, + ICON_VB_SELECT, + ICON_VB_TEXT, + ICON_VB_TEXT_CEN, + ICON_VB_INPUT_1LINE, + ICON_VB_INPUT_MLINE, + ICON_VB_CHECKBOX, + ICON_VB_SURR_RECT, + ICON_VB_BUTTON, + ICON_CLIPBOARD, + ICON_PAINT2, + ICON_FILE_BROKEN, + ICON_STOP_BLACK, + ICON_STOP_SMALL, + ICON_PAUSE_BLACK, + ICON_PAUSE_SMALL, + ICON_PLAY_BLACK, + ICON_PLAY_SMALL, + ICON_BROWSE_SMALL, + ICON_COUNT +}; + +enum CURSORTYPE +{ + CURSOR_DEFAULT, + CURSOR_WAIT, + CURSOR_IBEAM, + CURSOR_CROSS, + CURSOR_PENCIL, + CURSOR_COUNT, +}; + +enum +{ + FONT_TAMSYN_REGULAR, + FONT_TAMSYN_BOLD, + FONT_PAPERM, + FONT_FAMISANS, + FONT_BASIC, + FONT_GLCD, + FONT_TAMSYN_MED_REGULAR, + FONT_TAMSYN_MED_BOLD, + FONT_TAMSYN_SMALL_REGULAR, + FONT_TAMSYN_SMALL_BOLD, + //FONT_BIGTEST, + //FONT_BIGTEST2, + FONT_LAST, +}; + +typedef struct +{ + bool m_available; //if the vbe display is available + unsigned m_width, m_height, m_pitch;//bytes per row + int m_bitdepth; //bits per pixel, only values we support: 0=8, 1=16, 2=32 + bool m_dirty; //useful if the framebuffer won't directly be pushed to the screen + union { + uint32_t* m_framebuffer32; //for ease of addressing + uint16_t* m_framebuffer16; + uint8_t * m_framebuffer8; + }; + int m_pitch32, m_pitch16; //uint32_t's and uint16_t's per row. + Rectangle m_clipRect; +} +VBEData; + +typedef struct +{ + uint16_t width, height; + int16_t leftOffs, topOffs; + const uint32_t* bitmap; + bool m_transparency;//optimization + + bool m_resizeMode; + uint16_t boundsWidth, boundsHeight; + uint16_t mouseLockX, mouseLockY; +} +Cursor; + +#endif//_NANOSHELL_GRAPHICS_TYPES_H diff --git a/crt2/include/nanoshell/keyboard.h b/crt2/include/nanoshell/keyboard.h new file mode 100644 index 00000000..a325f0d2 --- /dev/null +++ b/crt2/include/nanoshell/keyboard.h @@ -0,0 +1,113 @@ +// nanoshell/keyboard.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _NANOSHELL_KEYBOARD__H +#define _NANOSHELL_KEYBOARD__H +#define _NANOSHELL_KEYBOARD__H + +#define KEY_UNDEFINED_0 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_HYPHEN KEY_MINUS +#define KEY_EQUALS 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_A 0x1e +#define KEY_B 0x30 +#define KEY_C 0x2e +#define KEY_D 0x20 +#define KEY_E 0x12 +#define KEY_F 0x21 +#define KEY_G 0x22 +#define KEY_H 0x23 +#define KEY_I 0x17 +#define KEY_J 0x24 +#define KEY_K 0x25 +#define KEY_L 0x26 +#define KEY_M 0x32 +#define KEY_N 0x31 +#define KEY_O 0x18 +#define KEY_P 0x19 +#define KEY_Q 0x10 +#define KEY_R 0x13 +#define KEY_S 0x1f +#define KEY_T 0x14 +#define KEY_U 0x16 +#define KEY_V 0x2f +#define KEY_W 0x11 +#define KEY_X 0x2d +#define KEY_Y 0x15 +#define KEY_Z 0x2c +#define KEY_BRACKET_LEFT 0x1a +#define KEY_BRACKET_RIGHT 0x1b +#define KEY_ENTER 0x1c +#define KEY_CONTROL 0x1d +#define KEY_CTRL KEY_CONTROL +#define KEY_SEMICOLON 0x27 +#define KEY_APOSTROPHE 0x28 +#define KEY_BACKTICK 0x29 +#define KEY_LSHIFT 0x2a +#define KEY_BACKSLASH 0x2b +#define KEY_COMMA 0x33 +#define KEY_DOT 0x34 +#define KEY_SLASH 0x35 +#define KEY_RSHIFT 0x36 +#define KEY_PRINTSCREEN 0x37 +#define KEY_ALT 0x38 +#define KEY_SPACE 0x39 +#define KEY_CAPSLOCK 0x3a +#define KEY_F1 0x3b +#define KEY_F2 0x3c +#define KEY_F3 0x3d +#define KEY_F4 0x3e +#define KEY_F5 0x3f +#define KEY_F6 0x40 +#define KEY_F7 0x41 +#define KEY_F8 0x42 +#define KEY_F9 0x43 +#define KEY_F10 0x44 +#define KEY_NUMLOCK 0x45 +#define KEY_SCROLLLOCK 0x46 +#define KEY_HOME 0x47 +#define KEY_ARROW_UP 0x48 +#define KEY_PAGEUP 0x49 +#define KEY_NUMPAD_MINUS 0x4a +#define KEY_NUMPAD_HYPHEN KEY_NUMPAD_MINUS +#define KEY_ARROW_LEFT 0x4b +#define KEY_LEFT KEY_ARROW_LEFT +#define KEY_UNDEFINED_4C 0x4c +#define KEY_ARROW_RIGHT 0x4d +#define KEY_RIGHT KEY_ARROW_RIGHT +#define KEY_NUMPAD_PLUS 0x4e +#define KEY_END 0x4f +#define KEY_ARROW_DOWN 0x50 +#define KEY_DOWN KEY_ARROW_DOWN +#define KEY_PAGEDOWN 0x51 +#define KEY_INSERT 0x52 +#define KEY_DELETE 0x53 +#define KEY_UNDEFINED_54 0x54 +#define KEY_UNDEFINED_55 0x55 +#define KEY_UNDEFINED_56 0x56 +#define KEY_F11 0x57 +#define KEY_F12 0x58 +#define KEY_UP KEY_ARROW_UP +#define KEY_MENU 0x5D + +#define SCANCODE_RELEASE 0x80 + +typedef uint8_t KeyState; +#define KEY_PRESSED ((KeyState) 1) +#define KEY_HELD ((KeyState) 2) +#define KEY_RELEASED ((KeyState) 0) + +#endif//_NANOSHELL_KEYBOARD__H diff --git a/crt2/include/nanoshell/lock.h b/crt2/include/nanoshell/lock.h new file mode 100644 index 00000000..57da06d6 --- /dev/null +++ b/crt2/include/nanoshell/lock.h @@ -0,0 +1,12 @@ +// nanoshell/lock.h +// Copyright (C) 2023 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _NANOSHELL_LOCK__H +#define _NANOSHELL_LOCK__H + +#include + +void LockAcquire (SafeLock *pLock); +void LockFree (SafeLock *pLock); + +#endif//_NANOSHELL_LOCK__H diff --git a/crt2/include/nanoshell/lock_types.h b/crt2/include/nanoshell/lock_types.h new file mode 100644 index 00000000..bc9b292a --- /dev/null +++ b/crt2/include/nanoshell/lock_types.h @@ -0,0 +1,15 @@ +// nanoshell/lock_types.h +// Copyright (C) 2023 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _NANOSHELL_LOCKTYPES__H +#define _NANOSHELL_LOCKTYPES__H + +typedef struct +{ + volatile bool m_held; + volatile void* m_task_owning_it; + volatile void* m_return_addr; +} +SafeLock; + +#endif//_NANOSHELL_LOCKTYPES__H diff --git a/crt2/include/nanoshell/mman_types.h b/crt2/include/nanoshell/mman_types.h new file mode 100644 index 00000000..4dc43bb0 --- /dev/null +++ b/crt2/include/nanoshell/mman_types.h @@ -0,0 +1,29 @@ +// nanoshell/mman_types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __MMAN_TYPES_H +#define __MMAN_TYPES_H + +#include + +// mmap() flags +#define PROT_NONE (0 << 0) +#define PROT_READ (1 << 0) +#define PROT_WRITE (1 << 1) +#define PROT_EXEC (1 << 2) //not applicable here + +#define MAP_FAILED ((void*) -1) //not NULL + +#define MAP_FILE (0 << 0) //retroactive, TODO +#define MAP_SHARED (1 << 0) //means changes in the mmapped region will be written back to the file on unmap/close +#define MAP_PRIVATE (1 << 1) //means changes won't be committed back to the source file +#define MAP_FIXED (1 << 4) //fixed memory mapping means that we really want it at 'addr'. +#define MAP_ANONYMOUS (1 << 5) //anonymous mapping, means that there's no file backing this mapping :) +#define MAP_ANON (1 << 5) //synonymous with "MAP_ANONYMOUS" +#define MAP_NORESERVE (0 << 0) //don't reserve swap space, irrelevent here + +#define MAP_DONTREPLACE (1 << 30) //don't clobber preexisting fixed mappings there. Used with MAP_FIXED to create... +#define MAP_FIXED_NOREPLACE (MAP_DONTREPLACE | MAP_FIXED) + + +#endif//__MMAN_TYPES_H \ No newline at end of file diff --git a/crt2/include/nanoshell/nanoshell.h b/crt2/include/nanoshell/nanoshell.h new file mode 100644 index 00000000..ac4f999b --- /dev/null +++ b/crt2/include/nanoshell/nanoshell.h @@ -0,0 +1,171 @@ +// nanoshell/nanoshell.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library + +// This non-portable include file includes everything from NanoShell. + +#ifndef _NANOSHELL___H +#define _NANOSHELL___H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// NanoShell specifics +#include +#include + +// Threading +void sleep(int ms); //not actually standard I don't think +void exit (int errcode); + +// Assertion + + +// Optimized memory operations to word width + +//NOTE: size must be 4 byte aligned!! +void ZeroMemory (void* bufptr1, size_t size); +void fmemcpy32 (void* restrict dest, const void* restrict src, size_t size); +void* fast_memset(void* bufptr, uint8_t val, size_t size); + +// File management + +// Graphics Interface + +// Window API +Window* CreateWindow (const char* title, int xPos, int yPos, int xSize, int ySize, WindowProc proc, int flags); +bool HandleMessages(Window* pWindow); +void DefaultWindowProc (Window* pWindow, int messageType, int parm1, int parm2); +void DestroyWindow (Window* pWindow); +int MessageBox (Window* pWindow, const char* pText, const char* pCaption, uint32_t type); +int AddControl(Window* pWindow, int type, Rectangle rect, const char* text, int comboID, int p1, int p2); +void SetScrollBarMin (Window *pWindow, int comboID, int min); +void SetScrollBarMax (Window *pWindow, int comboID, int max); +void SetScrollBarPos (Window *pWindow, int comboID, int pos); +int GetScrollBarPos (Window *pWindow, int comboID); +void AddElementToList (Window* pWindow, int comboID, const char* pText, int optionalIcon); +const char* GetElementStringFromList (Window* pWindow, int comboID, int index); +void RemoveElementFromList (Window* pWindow, int comboID, int elemIndex); +void SetListItemText(Window* pWindow, int comboID, int index, int icon, const char * pText); +void ResetList (Window* pWindow, int comboID); +void SetLabelText (Window *pWindow, int comboID, const char* pText); +void AddMenuBarItem (Window* pWindow, int menuBarControlId, int comboIdTo, int comboIdAs, const char* pText); +void SetHugeLabelText (Window *pWindow, int comboID, const char* pText); +void SetTextInputText(Window* pWindow, int comboID, const char* pText); +void SetWindowIcon (Window* pWindow, int icon); +void SetIcon (Window* pWindow, int comboID, int icon); +void SetWindowTitle(Window* pWindow, const char* pTitle); +void RegisterEvent(Window* pWindow, short evType, int parm1, int parm2); +void RegisterEventInsideWndProc(Window* pWindow, short evType, int parm1, int parm2); +int AddControlEx(Window* pWindow, int type, int anchor_mode, Rectangle rect, const char* text, int comboID, int p1, int p2); +bool TextInputQueryDirtyFlag(Window* pWindow, int comboID); +void TextInputClearDirtyFlag(Window* pWindow, int comboID); +const char* TextInputGetRawText(Window* pWindow, int comboID); +bool CheckboxGetChecked(Window* pWindow, int comboID); +void CheckboxSetChecked(Window* pWindow, int comboID, bool checked); +void SetTextInputText(Window* pWindow, int comboID, const char* pText); +void ShellAbout (const char* pText, int icon); +void RequestRepaint (Window *pWindow); +void RequestRepaintNew (Window *pWindow); +void PopupWindow (Window* pWindow, const char* newWindowTitle, int newWindowX, int newWindowY, int newWindowW, int newWindowH, WindowProc newWindowProc, int newFlags); +void PopupWindowEx(Window* pWindow, const char* newWindowTitle, int newWindowX, int newWindowY, int newWindowW, int newWindowH, WindowProc newWindowProc, int newFlags, void* pData); +uint32_t ColorInputBox (Window *pWindow, const char *pPrompt, const char *pCaption); +uint32_t GetThemingParameter (int type); +void SetThemingParameter (int type, uint32_t parm); +void SetWidgetEventHandler(Window *pWindow, int comboID, WidgetEventHandler handler); +WidgetEventHandler GetWidgetEventHandler(Window* pWindow, int comboID); +// The input boxes that return strings return a kernel memory region. Use MmKernelFree() instead of free() to free it. +char* InputBox (Window *pWindow, const char *pPrompt, const char *pCaption, const char *pDefaultText); +char* FilePickerBox(Window* pWindow, const char* pPrompt, const char* pCaption, const char* pDefaultText); +void CallControlCallback(Window * pWindow, int comboID, int event, int parm1, int parm2); +void TextInputSetMode (Window *pWindow, int comboID, int mode); +int GetScrollBarMin (Window *pWindow, int comboID); +int GetScrollBarMax (Window *pWindow, int comboID); +int GetSelectedIndexList (Window* pWindow, int comboID); +void SetSelectedIndexList (Window* pWindow, int comboID, int index); +int GetSelectedIndexTable(Window* pWindow, int comboID); +void SetSelectedIndexTable(Window* pWindow, int comboID, int selectedIndex); +int GetScrollTable(Window* pWindow, int comboID); +void SetScrollTable(Window* pWindow, int comboID, int scroll); +void AddTableRow(Window* pWindow, int comboID, const char* pText[], int optionalIcon); +void AddTableColumn(Window* pWindow, int comboID, const char* pText, int width); +bool GetRowStringsFromTable(Window* pWindow, int comboID, int index, const char * output[]); +void RemoveRowFromTable(Window* pWindow, int comboID, int elementIndex); +void ResetTable(Window* pWindow, int comboID); +const char* GetWindowTitle(Window* pWindow); +void* GetWindowData(Window* pWindow); +void SetWindowData(Window* pWindow, void* pData); +void GetWindowRect(Window* pWindow, Rectangle* pRectOut); +void ChangeCursor(Window* pWindow, int cursorID); +void SetImageCtlMode(Window* pWindow, int comboID, int mode); +void CallWindowCallbackAndControls(Window* pWindow, int eventType, int parm1, int parm2); +int GetWindowFlags(Window * pWindow); +void SetWindowFlags(Window * pWindow, int flags); +int AddTimer(Window* pWindow, int frequencyMs, int eventFired); +void DisarmTimer(Window* pWindow, int timerID); +void ChangeTimer(Window* pWindow, int newFrequencyMs /* = -1 */, int newEventFired /* = -1 */); +int UploadCursor(Image* pImage, int xOff, int yOff); +void ReleaseCursor(int cursorID); +Image* GetIconImage(int iconType, int size /* = -1 */); +Resource* GetResource(int resID); +Point GetMousePos(); +void SetImageCtlMode(Window* pWindow, int comboID, int mode); +void SetImageCtlColor(Window* pWindow, int comboID, uint32_t color); +void SetImageCtlCurrentImage(Window* pWindow, int comboID, Image* pImage); +Image* GetImageCtlCurrentImage(Window* pWindow, int comboID); +void ImageCtlZoomToFill(Window* pWindow, int comboID); +void SetControlDisabled(Window* pWindow, int comboID, bool flag); +void SetControlFocused (Window* pWindow, int comboID, bool flag); +void SetControlVisible (Window* pWindow, int comboID, bool flag); +void VidSetClipRect(Rectangle* rect); +void DrawEdge(Rectangle rect, int style, unsigned bg); +void DrawArrow(Rectangle rect, eArrowType arrowType, int flags, unsigned color); +void ProgBarSetProgress(Window* pWindow, int comboID, int prog); +void ProgBarSetMaxProg(Window* pWindow, int comboID, int max_prog); +void TextInputSetFont(Window *pWindow, int comboID, unsigned font); +void TextInputRequestCommand(Window *pWindow, int comboID, int command, void* parm); +void ComboBoxAddItem(Window* pWindow, int comboID, const char* item, int itemID, int iconID); +int ComboBoxGetSelectedItemID(Window* pWindow, int comboID); +void ComboBoxSetSelectedItemID(Window* pWindow, int comboID, int itemID); +void ComboBoxClearItems(Window* pWindow, int comboID); +bool IsControlFocused(Window* pWindow, int comboID); +bool IsControlDisabled(Window* pWindow, int comboID); +KeyState KbGetKeyState(unsigned char keycode); +Window* SpawnMenu(Window* pParentWindow, WindowMenu *root, int x, int y); + +// Internal C Compiler +int CcRunCCode(const char* pCode, int length); + +// NanoShell Versioning +int NsGetVersion (); +const char* GetVersionString(); + +// Shell +int ShellExecute (const char *pCommand); //for instance, "e " +int ShellExecuteResource(const char *pResourceID); //for instance, shell:stuff + +// Errors +int SetErrorNumber(int en); +int GetErrorNumber(); +int* GetErrorNumberPointer(); +#define ErrorNumber (*GetErrorNumberPointer()) + +// Kernel memory resource management. +// NOTE: Improper management of kernel memory resources will cause a leak that +// will persist over the rest of the OS' runtime, so use carefully!!!! +void* MmKernelAllocate(size_t sz); + +//note: Do not feed this function addresses from malloc(). +void MmKernelFree(void *pData); + + +#endif//_NANOSHELL___H \ No newline at end of file diff --git a/crt2/include/nanoshell/setjmp_types.h b/crt2/include/nanoshell/setjmp_types.h new file mode 100644 index 00000000..ec2ecaeb --- /dev/null +++ b/crt2/include/nanoshell/setjmp_types.h @@ -0,0 +1,16 @@ +// nanoshell/setjmp_types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _SETJMP_TYPES_H +#define _SETJMP_TYPES_H +// https://github.com/jezze/subc +typedef struct +{ + void *esp, *eax, *ebp; + void *ebx, *esi, *edi; +} +JumpBufferTag; + +typedef JumpBufferTag JumpBuffer[1], jmp_buf[1]; + +#endif//_SETJMP_TYPES_H diff --git a/crt2/include/nanoshell/stdio_types.h b/crt2/include/nanoshell/stdio_types.h new file mode 100644 index 00000000..04de4f5a --- /dev/null +++ b/crt2/include/nanoshell/stdio_types.h @@ -0,0 +1,22 @@ +// nanoshell/stdio_types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library + +#ifndef __NANOSHELL_STDIO_TYPES_H +#define __NANOSHELL_STDIO_TYPES_H + +#include + +#define EOF (-1) + +typedef struct +{ + int fd; + uint8_t ungetc_buf[4]; + int ungetc_buf_sz; + bool eof; + bool error; +} +FILE; + +#endif//__NANOSHELL_STDIO_TYPES_H diff --git a/crt2/include/nanoshell/stdlib_types.h b/crt2/include/nanoshell/stdlib_types.h new file mode 100644 index 00000000..91ff151c --- /dev/null +++ b/crt2/include/nanoshell/stdlib_types.h @@ -0,0 +1,15 @@ +// nanoshell/stdlib_types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library + +#ifndef __NANOSHELL_STDLIB_TYPES_H +#define __NANOSHELL_STDLIB_TYPES_H + +#include + +#define RAND_MAX (0x7FFFFFFF) + +typedef int(*ComparisonFunc) (const void*, const void*); +typedef int(*ComparisonReentrantFunc) (const void*, const void*, void*); + +#endif//__NANOSHELL_STDLIB_TYPES_H \ No newline at end of file diff --git a/crt2/include/nanoshell/time_types.h b/crt2/include/nanoshell/time_types.h new file mode 100644 index 00000000..f8c1c587 --- /dev/null +++ b/crt2/include/nanoshell/time_types.h @@ -0,0 +1,73 @@ +// nanoshell/time_types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _TIME_TYPES_H +#define _TIME_TYPES_H + +#include + +typedef long time_t; + +struct timespec +{ + time_t tv_sec; + long tv_nsec; +}; + +struct timeval +{ + time_t tv_sec; + long tv_usec; +}; + +struct tm +{ + int tm_sec; // Seconds after the minute. [0, 59] + int tm_min; // Minutes after the hour. [0, 59] + int tm_hour; // Hours since midnight. [0, 23] + int tm_mday; // Day of the month. [1, 31] + int tm_mon; // Months since January. [0, 11] + int tm_year; // Years since 1900. (so, 2022 would be represented as 122) + int tm_wday; // Days since Sunday. [0, 6]. Sunday = 0. + int tm_yday; // Days since January 1st. [0, 365] (Day 365 = December 31st, on a leap year) + int tm_isdst; // Daylight savings time flag. + long int tm_gmtoff; // GNU extension: The offset from GMT in seconds. + const char *tm_zone; // GNU extension: The name of the time zone. +}; + +typedef struct +{ + int seconds, + minutes, + hours, + weekday, + day, + month, + year, + statusA, + statusB; +} +TimeStruct; + +TimeStruct *GetTime (); + +// Get the time (in milliseconds) since the OS has been started. +int GetTickCount(); + +int GetEpochTime(); +int GetEpochTimeFromTimeStruct(TimeStruct* ts); +void GetHumanTimeFromEpoch(int utime, TimeStruct* pOut); + +// Time manipulation functions. +/* +TODO + +double difftime(time_t a, time_t b); +time_t mktime (struct tm* ptr); +time_t time (time_t* timer); +int timespec_get(struct timespec* ptr, int base); +struct tm* gmtime_r(const time_t* timer, struct tm* result); +struct tm* gmtime (const time_t* timer); +*/ + +#endif//_TIME_TYPES_H diff --git a/crt2/include/nanoshell/types.h b/crt2/include/nanoshell/types.h new file mode 100644 index 00000000..9fc41e9b --- /dev/null +++ b/crt2/include/nanoshell/types.h @@ -0,0 +1,740 @@ +// nanoshell/types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _NANOSHELL_TYPES__H +#define _NANOSHELL_TYPES__H + +// Basic includes everyone should have +#include +#include +#include +#include +#include + +// Include other type files. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define false 0 +#define true 1 + +#define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array)) + +#define UNUSED __attribute__((unused)) + +// Defines +#define WIN_KB_BUF_SIZE 512 + +//#define TITLE_BAR_HEIGHT 18 + +#define BACKGROUND_COLOR (GetThemingParameter(P_BACKGROUND_COLOR )) +#define BUTTON_MIDDLE_COLOR (GetThemingParameter(P_BUTTON_MIDDLE_COLOR )) +#define WINDOW_BACKGD_COLOR (GetThemingParameter(P_WINDOW_BACKGD_COLOR )) +#define WINDOW_TITLE_ACTIVE_COLOR (GetThemingParameter(P_WINDOW_TITLE_ACTIVE_COLOR )) +#define WINDOW_TITLE_INACTIVE_COLOR (GetThemingParameter(P_WINDOW_TITLE_INACTIVE_COLOR )) +#define WINDOW_TITLE_ACTIVE_COLOR_B (GetThemingParameter(P_WINDOW_TITLE_ACTIVE_COLOR_B )) +#define WINDOW_TITLE_INACTIVE_COLOR_B (GetThemingParameter(P_WINDOW_TITLE_INACTIVE_COLOR_B )) +#define WINDOW_TITLE_TEXT_COLOR_SHADOW (GetThemingParameter(P_WINDOW_TITLE_TEXT_COLOR_SHADOW )) +#define WINDOW_TITLE_TEXT_COLOR (GetThemingParameter(P_WINDOW_TITLE_TEXT_COLOR )) +#define WINDOW_TEXT_COLOR (GetThemingParameter(P_WINDOW_TEXT_COLOR )) +#define WINDOW_TEXT_COLOR_LIGHT (GetThemingParameter(P_WINDOW_TEXT_COLOR_LIGHT )) +#define SYSTEM_FONT ((int)GetThemingParameter(P_SYSTEM_FONT )) +#define TITLE_BAR_HEIGHT ((int)GetThemingParameter(P_TITLE_BAR_HEIGHT )) +#define TITLE_BAR_FONT ((int)GetThemingParameter(P_TITLE_BAR_FONT )) +#define SELECTED_MENU_ITEM_COLOR (GetThemingParameter(P_SELECTED_MENU_ITEM_COLOR )) +#define SELECTED_MENU_ITEM_COLOR_B (GetThemingParameter(P_SELECTED_MENU_ITEM_COLOR_B )) +#define WINDOW_BORDER_COLOR (GetThemingParameter(P_WINDOW_BORDER_COLOR )) +#define MENU_BAR_HEIGHT ((int)GetThemingParameter(P_MENU_BAR_HEIGHT )) +#define MENU_ITEM_HEIGHT ((int)GetThemingParameter(P_MENU_ITEM_HEIGHT )) +#define BORDER_SIZE ((int)GetThemingParameter(P_BORDER_SIZE )) +#define BUTTON_HILITE_COLOR (GetThemingParameter(P_BUTTON_HILITE_COLOR )) +#define BUTTON_SHADOW_COLOR (GetThemingParameter(P_BUTTON_SHADOW_COLOR )) +#define BUTTON_EDGE_COLOR (GetThemingParameter(P_BUTTON_EDGE_COLOR )) +#define BUTTON_HOVER_COLOR (GetThemingParameter(P_BUTTON_HOVER_COLOR )) +#define SCROLL_BAR_SIZE ((int)GetThemingParameter(P_SCROLL_BAR_SIZE )) +#define MENU_BAR_SELECTION_COLOR (GetThemingParameter(P_MENU_BAR_SELECTION_COLOR )) +#define SELECTED_ITEM_COLOR (GetThemingParameter(P_SELECTED_ITEM_COLOR )) +#define SELECTED_TEXT_COLOR (GetThemingParameter(P_SELECTED_TEXT_COLOR )) +#define DESELECTED_TEXT_COLOR (GetThemingParameter(P_DESELECTED_TEXT_COLOR )) +#define LIST_BACKGD_COLOR (GetThemingParameter(P_LIST_BACKGD_COLOR )) +#define TOOLTIP_BACKGD_COLOR (GetThemingParameter(P_TOOLTIP_BACKGD_COLOR )) +#define TOOLTIP_TEXT_COLOR (GetThemingParameter(P_TOOLTIP_TEXT_COLOR )) +#define SCROLL_BAR_BACKGD_COLOR (GetThemingParameter(P_SCROLL_BAR_BACKGD_COLOR )) +#define SELECTED_MENU_ITEM_TEXT_COLOR (GetThemingParameter(P_SELECTED_MENU_ITEM_TEXT_COLOR )) +#define DESELECTED_MENU_ITEM_TEXT_COLOR (GetThemingParameter(P_DESELECTED_MENU_ITEM_TEXT_COLOR )) +#define TABLE_VIEW_ALT_ROW_COLOR (GetThemingParameter(P_TABLE_VIEW_ALT_ROW_COLOR )) +#define BUTTON_XSHADOW_COLOR (GetThemingParameter(P_BUTTON_XSHADOW_COLOR )) +#define CAPTION_BUTTON_ICON_COLOR (GetThemingParameter(P_CAPTION_BUTTON_ICON_COLOR )) + +// Mark your system callbacks with this anyway!!! +#define CALLBACK + +#define MAKE_MOUSE_PARM(x, y) ((x)<<16|(y)) +#define GET_X_PARM(parm1) (parm1>>16) +#define GET_Y_PARM(parm1) (parm1&0xFFFF) + +#define TEXTEDIT_MULTILINE (1) +#define TEXTEDIT_LINENUMS (2) +#define TEXTEDIT_READONLY (4) +#define TEXTEDIT_STYLING (8) +#define TEXTEDIT_SYNTHILT (16) + +#define IMAGECTL_PAN (1) +#define IMAGECTL_ZOOM (2) +#define IMAGECTL_PEN (4) +#define IMAGECTL_FILL (8) + +// By default, the control's anchoring mode is: +// ANCHOR_LEFT_TO_LEFT | ANCHOR_RIGHT_TO_LEFT | ANCHOR_TOP_TO_TOP | ANCHOR_BOTTOM_TO_TOP + +// If the control's left edge anchors to the window's right edge. +// If this bit isn't set, the control's left edge anchors to the window's left edge. +#define ANCHOR_LEFT_TO_RIGHT 1 +// If the control's right edge anchors to the window's right edge. +// If this bit isn't set, the control's right edge anchors to the window's left edge. +#define ANCHOR_RIGHT_TO_RIGHT 2 +// If the control's top edge anchors to the window's bottom edge. +// If this bit isn't set, the control's top edge anchors to the window's top edge. +#define ANCHOR_TOP_TO_BOTTOM 4 +// If the control's bottom edge anchors to the window's bottom edge. +// If this bit isn't set, the control's bottom edge anchors to the window's top edge. +#define ANCHOR_BOTTOM_TO_BOTTOM 8 + +#define WF_NOCLOSE 0x00000001//Disable close button +#define WF_FROZEN 0x00000002//Freeze window +#define WF_NOTITLE 0x00000004//Disable title +#define WF_NOBORDER 0x00000008//Disable border +#define WF_NOMINIMZ 0x00000010//Disable minimize button +#define WF_ALWRESIZ 0x00000020//Allow resize +#define WF_NOMAXIMZ 0x00000080//Disable maximize button +#define WF_FLATBORD 0x00000100//Use a flat border instead of the regular border +#define WF_NOWAITWM 0x00000200//Prevent waiting for the window manager to update. Useful for games (1) +#define WF_BACKGRND 0x00000400//The window is on a separate 'background' layer, behind normal windows. +#define WF_FOREGRND 0x00000800//The window is on a separate 'foreground' layer, in front of normal windows. +#define WF_SYSPOPUP 0x10000000//System Popup (omit from taskbar) + +#define WINDOWS_MAX 256 +#define WINDOW_TITLE_MAX 250 +#define EVENT_QUEUE_MAX 256 + +#define KB_BUF_SIZE 512 + +#define LIST_ITEM_HEIGHT 16 +#define ICON_ITEM_WIDTH 90 +#define ICON_ITEM_HEIGHT 60 + +#define MB_OK 0x00000000 //The message box contains one push button: OK. This is the default. +#define MB_OKCANCEL 0x00000001 //The message box contains two push buttons: OK and Cancel. +#define MB_ABORTRETRYIGNORE 0x00000002 //The message box contains three push buttons: Abort, Retry and Ignore. +#define MB_YESNOCANCEL 0x00000003 //The message box contains three push buttons: Yes, No, and Cancel. +#define MB_YESNO 0x00000004 //The message box contains two push buttons: Yes, and No. +#define MB_RETRYCANCEL 0x00000005 //The message box contains two push buttons: Retry and Cancel. +#define MB_CANCELTRYCONTINUE 0x00000006 //The message box contains three push buttons: Cancel, Retry, and Continue. +#define MB_RESTART 0x00000007 //The message box contains one push button: Restart. + +// This flag tells the operating system that it may choose where to place a window. +// If the xPos and yPos are bigger than or equal to zero, the application tells the OS where it should place the window. +// The OS will use this as a guideline, for example, if an application wants to go off the screen, the OS +// will reposition its window to be fully inside the screen boundaries. +#define CW_AUTOPOSITION (-1) + +#define WINDOW_MIN_WIDTH (32) //that's already very small. +#define WINDOW_MIN_HEIGHT (3+TITLE_BAR_HEIGHT) + +#define WINDOW_MINIMIZED_WIDTH (160) +#define WINDOW_MINIMIZED_HEIGHT (3+TITLE_BAR_HEIGHT) + +#define TEXTSTYLE_HCENTERED (1) +#define TEXTSTYLE_VCENTERED (2) +#define TEXTSTYLE_WORDWRAPPED (4) +#define TEXTSTYLE_RJUSTIFY (8) +#define TEXTSTYLE_FORCEBGCOL (16)//VidDrawText does nothing with this flag, it's used for CONTROL_TEXTCENTER. +#define TEXTSTYLE_DJUSTIFY (32) + +#define GetImage(res) ((Image*)((res)->m_data)) +#define GetString(res) ((const char*)((res)->m_data)) + +#define DRE_RAISEDINNER (1 << 0) +#define DRE_SUNKENINNER (1 << 1) +#define DRE_RAISEDOUTER (1 << 2) +#define DRE_SUNKENOUTER (1 << 3) +#define DRE_BLACKOUTER (1 << 4) // takes priority over all these + +#define DRE_OUTER (DRE_RAISEDOUTER | DRE_SUNKENOUTER) +#define DRE_INNER (DRE_RAISEDINNER | DRE_SUNKENINNER) + +#define DRE_RAISED (DRE_RAISEDINNER | DRE_RAISEDOUTER) +#define DRE_SUNKEN (DRE_SUNKENINNER | DRE_SUNKENOUTER) + +#define DRE_FILLED (1 << 24) // 'bg' is ignored if this is not set +#define DRE_FLAT (1 << 25) // flat border. +#define DRE_HOT (1 << 26) // the button is hovered + +#define DRE_LEFT (1 << 27) +#define DRE_TOP (1 << 28) +#define DRE_RIGHT (1 << 29) +#define DRE_BOTTOM (1 << 30) +#define DRE_RECT (15 << 27) + +#define DRA_IGNOREXSIZE (1 << 0) // Ignores the width of the rectangle. +#define DRA_IGNOREYSIZE (1 << 1) // Ignores the height of the rectangle. + +#define DRA_CENTERX (1 << 2) // Center along the X axis. +#define DRA_CENTERY (1 << 3) // Center along the Y axis. + +// DRA_IGNOREXSIZE | DRA_IGNOREYSIZE means that both sizes are ignored, so the default size of ARROW_SIZE will be used. +#define DRA_IGNORESIZE (DRA_IGNOREXSIZE | DRA_IGNOREYSIZE) +#define DRA_CENTERALL (DRA_CENTERX | DRA_CENTERY) + +// Structs and enums + +#define DefaultConsoleColor 0x0F + +enum ConsoleType +{ + CONSOLE_TYPE_NONE, // uninitialized + CONSOLE_TYPE_TEXT, // always full screen + CONSOLE_TYPE_FRAMEBUFFER, // can either be the entire screen or just a portion of it. TODO + CONSOLE_TYPE_SERIAL, // just plain old serial + CONSOLE_TYPE_E9HACK, // Port E9 hack - qemu and bochs support this. + CONSOLE_TYPE_WINDOW, +}; + +enum +{ + EVENT_NULL, + EVENT_CREATE, // Shall be only called once, when a window or widget is created. + EVENT_DESTROY, // Shall be only called once, when a window or widget is destroyed. + EVENT_PAINT, + EVENT_MOVE, + EVENT_SIZE, + EVENT_ACTIVATE, + EVENT_SETFOCUS, + EVENT_KILLFOCUS, + EVENT_UPDATE, + EVENT_MOVECURSOR, + EVENT_CLICKCURSOR, + EVENT_RELEASECURSOR, + EVENT_COMMAND, + EVENT_KEYPRESS, + EVENT_CLOSE, + EVENT_KEYRAW, + EVENT_MINIMIZE,//do not call this normally. + EVENT_UNMINIMIZE, + EVENT_UPDATE2, + EVENT_MENU_CLOSE, + EVENT_CLICK_CHAR, + EVENT_MAXIMIZE, + EVENT_UNMAXIMIZE, + EVENT_IMAGE_REFRESH, + EVENT_RIGHTCLICK, + EVENT_RIGHTCLICKRELEASE, + EVENT_CHECKBOX, + EVENT_SCROLLDONE, + EVENT_MAX, + + EVENT_USER = 0x1000, +}; + +enum // eResourceType +{ + RES_NONE, + RES_STRING, + RES_ICON, + RES_BITMAP, + RES_BLOB, +}; +typedef int eResourceType; + +// Text Edit commands. TextInputRequestCommand +enum +{ + // clipboard commands. `parm` is ignored. + TEDC_PASTE, + TEDC_CUT, + TEDC_COPY, + + TEDC_INSERT, // inserts an arbitrary piece of text. Requires a parameter in `parm`. + + TEDC_GOTOLINE, // `parm` is here treated as a pointer to an integer + TEDC_GOTOOFFSET, // same here + TEDC_UNDO, + TEDC_SELECT_ALL, + TEDC_DELETE, +}; + +//NOTE WHEN WORKING WITH CONTROLS: +//While yes, the window manager technically supports negative comboIDs, you're not supposed +//to use them. They are used internally by other controls (for example list views and text input views). + +enum +{ + //A null control. Does nothing. + CONTROL_NONE, + //A text control printing text in its top-left corner. + CONTROL_TEXT, + //A control displaying an icon in the center of the rectangle. + CONTROL_ICON, + //A clickable button which triggers an EVENT_COMMAND with its comboID + //as its first parm. + CONTROL_BUTTON, + //A text input field. Not Finished + CONTROL_TEXTINPUT, + //A checkbox. Not Finished. + CONTROL_CHECKBOX, + //A clickable label, which renders its text in the center-left. + //Does the same as the CONTROL_BUTTON. + CONTROL_CLICKLABEL, + //A text control printing text in the center of the rectangle. + CONTROL_TEXTCENTER, + //A clickable button which triggers an event based on this->m_parm1 + //with its comboID as its first parm. + CONTROL_BUTTON_EVENT, + //A list view. Complicated. + CONTROL_LISTVIEW, + //A vertical scroll bar. + CONTROL_VSCROLLBAR, + //A horizontal scroll bar. + CONTROL_HSCROLLBAR, + //A menu bar attached to the top of a window. + //Adding more than one control is considered UB + CONTROL_MENUBAR, + //A text control printing big text (>127 chars) + CONTROL_TEXTHUGE, + //Same as CONTROL_LISTVIEW but with bigger icons. + CONTROL_ICONVIEW, + //Does nothing except surround other controls with a rectangle. Useful for grouping settings. + CONTROL_SURROUND_RECT, + //Button with a colored background (parm2) + CONTROL_BUTTON_COLORED, + //Button as part of a list + CONTROL_BUTTON_LIST, + //Button with an icon on top. Parm1= icon type, Parm2= icon size (16 or 32) + CONTROL_BUTTON_ICON, + //Button with an icon on top. Parm1= icon type, Parm2= icon size (16 or 32) + CONTROL_BUTTON_ICON_BAR, + //A simple line control + CONTROL_SIMPLE_HLINE, + //Image control. A _valid_ pointer to an Image structure must be passed into parm1. + //When creating the control, the image gets duplicated, so the caller may free/dispose of + //the old image. The system will get rid of its own copy when the control gets destroyed. + CONTROL_IMAGE, + //Task list control + CONTROL_TASKLIST, + //Same as CONTROL_ICONVIEW but with draggable icons. + CONTROL_ICONVIEWDRAG, + //A table view. Even more complicated. + CONTROL_TABLEVIEW, + //Checkable icon button. + CONTROL_BUTTON_ICON_CHECKABLE, + //This control is purely to identify how many controls we support + //currently. This control is unsupported and will crash your application + //if you use this. + CONTROL_COUNT, + + CONTROL_SIMPLE_VLINE = -CONTROL_SIMPLE_HLINE, // macro for CONTROL_SIMPLE_HLINE with parm1 = 1 +}; + +enum +{ + MBID_OK = 0x10010, + MBID_CANCEL, + MBID_ABORT, + MBID_RETRY, + MBID_IGNORE, + MBID_YES, + MBID_NO, + MBID_TRY_AGAIN, + MBID_CONTINUE, + MBID_COUNT, +}; + +enum { + P_BLACK, + P_BACKGROUND_COLOR, + P_BUTTON_MIDDLE_COLOR, + P_WINDOW_BACKGD_COLOR, + P_WINDOW_BORDER_COLOR, + P_WINDOW_TITLE_ACTIVE_COLOR, + P_WINDOW_TITLE_INACTIVE_COLOR, + P_WINDOW_TITLE_ACTIVE_COLOR_B, + P_WINDOW_TITLE_INACTIVE_COLOR_B, + P_WINDOW_TITLE_TEXT_COLOR_SHADOW, + P_WINDOW_TITLE_TEXT_COLOR, + P_WINDOW_TEXT_COLOR, + P_WINDOW_TEXT_COLOR_LIGHT, + P_SYSTEM_FONT, + P_TITLE_BAR_HEIGHT, + P_TITLE_BAR_FONT, + P_SELECTED_MENU_ITEM_COLOR, + P_SELECTED_MENU_ITEM_COLOR_B, + P_MENU_BAR_HEIGHT, + P_BORDER_SIZE, + P_BUTTON_HILITE_COLOR, + P_BUTTON_SHADOW_COLOR, + P_BUTTON_EDGE_COLOR, + P_BUTTON_HOVER_COLOR, + P_SCROLL_BAR_SIZE, + P_MENU_BAR_SELECTION_COLOR, + P_SELECTED_ITEM_COLOR, + P_SELECTED_TEXT_COLOR, + P_DESELECTED_TEXT_COLOR, + P_LIST_BACKGD_COLOR, + P_TOOLTIP_BACKGD_COLOR, + P_TOOLTIP_TEXT_COLOR, + P_SCROLL_BAR_BACKGD_COLOR, + P_SELECTED_MENU_ITEM_TEXT_COLOR, + P_DESELECTED_MENU_ITEM_TEXT_COLOR, + P_TABLE_VIEW_ALT_ROW_COLOR, + P_MENU_ITEM_HEIGHT, + P_BUTTON_XSHADOW_COLOR, + P_CAPTION_BUTTON_ICON_COLOR, +}; + +enum +{ + /*0x80*/TIST_BOLD = '\x80', + /*0x81*/TIST_UNDERLINE, + /*0x82*/TIST_ITALIC, + /*0x83*/TIST_RED, + /*0x84*/TIST_BLUE, + /*0x85*/TIST_GREEN, + /*0x86*/TIST_LINK, + /*0x87*/TIST_UNFORMAT, + /*0x88*/TIST_UNBOLD, + /*0x89*/TIST_UNITALIC, + /*0x8A*/TIST_UNUNDERLINE, + /*0x8B*/TIST_UNCOLOR, + /*0x8C*/TIST_UNLINK, + /*0x8D*/TIST_COUNT, +}; + +enum +{ + CLIPBOARD_DATA_NONE, + CLIPBOARD_DATA_INTEGER, + CLIPBOARD_DATA_BINARY, + CLIPBOARD_DATA_TEXT, + CLIPBOARD_DATA_LARGE_TEXT, + + // Add more clipboard data types here. Unknown clipboard data types will be treated as generic binaries +}; + +typedef enum eArrowType +{ + DRA_UP, + DRA_DOWN, + DRA_LEFT, + DRA_RIGHT, +} +eArrowType; + +//Console +typedef struct ConsoleStruct +{ + int type; // ConsoleType enum + int width, height; // width and height + uint16_t *textBuffer; // unused in fb mode + uint16_t color; // colors + int curX, curY; // cursor X and Y positions + bool pushOrWrap;// check if we should push whole screen up, or clear&wrap + VBEData* m_vbeData;//vbe data to switch to when drawing, ONLY APPLIES TO CONSOLE_TYPE_WINDOW!! + int offX, offY; + int font; + int cwidth, cheight; + bool m_dirty; + char m_inputBuffer[KB_BUF_SIZE]; + int m_inputBufferBeg, m_inputBufferEnd; + int m_cursorFlashTimer, m_cursorFlashState; +} +Console; + + +struct WindowStruct; +struct ControlStruct; +typedef bool (*WidgetEventHandler) (struct ControlStruct*, int eventType, int parm1, int parm2, struct WindowStruct* parentWindow); +typedef void (*WindowProc) (struct WindowStruct*, int, int, int); + +typedef struct +{ + int m_icon;//can be blank + char m_contents [128]; +} +ListItem; + +typedef struct +{ + bool m_hasIcons; + int m_elementCount, m_capacity; + int m_scrollY; + int m_highlightedElementIdx; + ListItem *m_pItems; +} +ListViewData; + +typedef struct +{ + bool m_isBeingDragged, m_clickedBefore; + bool m_yMinButton, m_yMaxButton; + int m_min, m_max, m_pos, m_dbi; +} +ScrollBarData; + +typedef struct tagMenuBarTreeItem +{ + int m_comboID;//can be searchable + int m_childrenCount, + m_childrenCapacity;//if childrenCount reaches this and we need to add another, double this + struct tagMenuBarTreeItem* m_childrenArray; + char m_text [104]; + //if this value is set, it gets drawn if this is an item part of the root tree, or the parent is open too. + bool m_isOpen; +} +MenuBarTreeItem; + +typedef struct +{ + bool m_clicked, + m_hovered; +} +ButtonData; + +typedef struct +{ + MenuBarTreeItem m_root; +} +MenuBarData; + +typedef struct +{ + Image *pImage; + uint32_t nCurrentColor; + //if parm2 flag IMAGECTL_PAN is set, this has an effect. By default it is 0 + int nCurPosX, nCurPosY; + //to track cursor movement delta + int nLastXGot, nLastYGot; + //if parm2 flag IMAGECTL_ZOOM is set, this has an effect on the resulting image. By default it is the same as nWidth. + //to get height, you do (int)(((long long)nHeight * nZoomedWidth) / nWidth) + int nZoomedWidth; +} +ImageCtlData; + +typedef struct +{ + bool m_focused; + bool m_dirty;//Has it been changed since the dirty flag was set to false? + bool m_onlyOneLine, m_showLineNumbers;//note that these are mutually exclusive, but both can be turned off + int m_textCapacity, m_textLength;//The text length needs to be 1 less than the text capacity. + //If the text capacity is 65, for example, the textLength may not be bigger than 64. + int m_textCursorIndex, m_textCursorSelStart, m_textCursorSelEnd, + m_scrollY; + char* m_pText; + bool m_readOnly; + bool m_enableStyling; +} +TextInputData; + +typedef struct +{ + bool m_clicked; + bool m_checked; +} +CheckBoxData; + +typedef struct ControlStruct +{ + bool m_active; + int m_type;//CONTROL_XXX + int m_parm1, m_parm2; + int m_comboID; + char m_text[128]; + void* m_dataPtr; + Rectangle m_rect; + bool m_bMarkedForDeletion; + bool m_bFocused; + bool m_bVisible; + + //data for controls: + union + { + ListViewData m_listViewData; + ScrollBarData m_scrollBarData; + ButtonData m_buttonData; + MenuBarData m_menuBarData; + TextInputData m_textInputData; + CheckBoxData m_checkBoxData; + ImageCtlData m_imageCtlData; + }; + + int m_anchorMode; + + //event handler + WidgetEventHandler OnEvent; + + // A rect that was tried. This is what the control's size _should_ be, + // but due to some limitation m_triedRect may not match m_rect. + // The smallest rectangle a control can occupy is 10x10. + Rectangle m_triedRect; + + bool m_bDisabled; +} +Control; + +// DON'T rely on this!!! This is an internal kernel struct and can be changed. + +typedef struct WindowStruct +{ + bool m_used; + bool m_minimized; + bool m_hidden; + bool m_isBeingDragged; + bool m_isSelected; + + bool m_renderFinished; + + char* m_title; + + int m_flags; + + WindowProc m_callback; + Rectangle m_rect; + Rectangle m_rectBackup; + VBEData m_vbeData; + + int m_iconID; + + bool m_eventQueueLockUnused; // left to keep compatibity with old ELFs that modify the window structure directly + short* m_eventQueue; + int* m_eventQueueParm1; + int* m_eventQueueParm2; + //short m_eventQueue[EVENT_QUEUE_MAX]; + //int m_eventQueueParm1[EVENT_QUEUE_MAX]; + //int m_eventQueueParm2[EVENT_QUEUE_MAX]; + int m_eventQueueSize; + + int m_minWidth, m_minHeight; + + bool m_markedForDeletion; + + Control* m_pControlArray; + int m_controlArrayLen; + + void* m_data; //user data + + void *m_pOwnerThread, + *m_pSubThread;//in case you ever want to use this + + Console* m_consoleToFocusKeyInputsTo; + + bool m_bWindowManagerUpdated; + + int m_cursorID; + + bool m_maximized; + + // Raw input buffer. + char* m_inputBuffer; + int m_inputBufferBeg, m_inputBufferEnd; + + bool m_clickedInside; + + SafeLock m_EventQueueLock; + + Rectangle m_taskbarRect; + + Cursor m_customCursor; + + int m_frequentWindowRenders; + int m_lastSentPaintEventExternallyWhen; + + int m_cursorID_backup; + + int m_lastHandledMessagesWhen; + + //these two booleans are updated by UpdateDepthBuffer() internally + //if none of the window's pixels are visible + bool m_bObscured; + //if all of the window's pixels are visible at the same time + //(we can optimize drawing by just VidBitBlitting it directly + //to the screen, instead of taking occlusion into account) + bool m_bForemost; + + //avoid a data race while resizing the screen + SafeLock m_screenLock; +} Window; + +typedef Window* PWINDOW; + + +//BetterStrTok: https://github.com/iProgramMC/BetterStrTok +typedef struct { + bool m_bInitted; + char*m_pContinuation; + char*m_pReturnValue; +} TokenState; + +typedef struct +{ + SafeLock m_lock; + + int m_type; + char m_short_str[256]; + int m_blob_size; + + union { + int m_int_data; + void *m_generic_data_ptr; + char *m_char_str; + }; +} +ClipboardVariant; + +typedef struct +{ + // The resource's ID. + int m_id; + + // The type of resource. + eResourceType m_type; + + // The size of the binary data following this resource. + int m_size; + + // The data after the resource. + char m_data[]; +} +Resource; + +typedef struct MenuEntry +{ + Window* pWindow; + struct MenuEntry* pMenuEntries; + int nMenuEntries; + int nMenuComboID; + int nOrigCtlComboID; + char sText[100]; + bool bOpen; + bool bHasIcons; + int nLineSeparators; + Window* pOpenWindow; + int nIconID; + int nWidth; // The width of the menu window (if this has children) + int nHeight; // The height of the menu window + int nItemWidth; // The width of this item when the parent menu is opened. If 0, this fills to the width. + int nItemX; // The X position of the item. + int nItemY; // The Y position of the item. If 0, this is automatically laid out. + bool bDisabled; + bool bPrivate; // uses a private event rather than a public one. +} +WindowMenu; + +#endif//_NANOSHELL_TYPES__H \ No newline at end of file diff --git a/crt2/include/nanoshell/unistd_types.h b/crt2/include/nanoshell/unistd_types.h new file mode 100644 index 00000000..a957e330 --- /dev/null +++ b/crt2/include/nanoshell/unistd_types.h @@ -0,0 +1,72 @@ +// nanoshell/unistd_types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _NANOSHELL_UNISTD_TYPES__H +#define _NANOSHELL_UNISTD_TYPES__H + +#include + +#define PATH_MAX (260) +#define PATH_SEP ('/') +#define PATH_THISDIR (".") +#define PATH_PARENTDIR ("..") + +#define PERM_READ (1) +#define PERM_WRITE (2) +#define PERM_EXEC (4) + +#define O_RDONLY (1) +#define O_WRONLY (2) +#define O_RDWR (O_RDONLY | O_WRONLY) +#define O_APPEND (4) +#define O_CREAT (8) +#define O_NONBLOCK (16) +#define O_TRUNC (32) +#define O_EXEC (1024) + +//lseek whences +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +typedef struct +{ + uint32_t m_type; + uint32_t m_size; + uint32_t m_blocks; + uint32_t m_inode; + + uint32_t m_perms; + uint32_t m_modifyTime; + uint32_t m_createTime; +} +StatResult; + +enum +{ + FILE_TYPE_NONE = 0, + FILE_TYPE_FILE, + FILE_TYPE_CHAR_DEVICE, + FILE_TYPE_BLOCK_DEVICE, + FILE_TYPE_PIPE, + FILE_TYPE_SYMBOLIC_LINK, + FILE_TYPE_DIRECTORY = 8, + FILE_TYPE_MOUNTPOINT = 16, //to be OR'd into the other flags +}; + +enum +{ + IOCTL_NO_OP, // This can be used to test if the device actually supports I/O control. Does nothing. + + // Define the starting places of I/O controls for each device. + IOCTL_TERMINAL_START = 10000, + IOCTL_SOUNDDEV_START = 20000, + //... + + IOCTL_TERMINAL_GET_SIZE = IOCTL_TERMINAL_START, // argp points to a Point structure, which will get filled in. + IOCTL_TERMINAL_SET_ECHO_INPUT, // enable or disable echoing input in CoGetString() + + IOCTL_SOUNDDEV_SET_SAMPLE_RATE = IOCTL_SOUNDDEV_START, // Set the sample rate of an audio playback device. +}; + +#endif//_NANOSHELL_UNISTD_TYPES__H \ No newline at end of file diff --git a/crt2/include/nsstandard.h b/crt2/include/nsstandard.h new file mode 100644 index 00000000..27f900f9 --- /dev/null +++ b/crt2/include/nsstandard.h @@ -0,0 +1,4 @@ +// nsstandard.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#include diff --git a/crt2/include/nsstructs.h b/crt2/include/nsstructs.h new file mode 100644 index 00000000..bb410bfe --- /dev/null +++ b/crt2/include/nsstructs.h @@ -0,0 +1,4 @@ +// nsstructs.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#include diff --git a/crt2/include/setjmp.h b/crt2/include/setjmp.h new file mode 100644 index 00000000..28439a54 --- /dev/null +++ b/crt2/include/setjmp.h @@ -0,0 +1,16 @@ +// setjmp.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _SETJMP___H +#define _SETJMP___H + +#include + +__attribute__((returns_twice)) int setjmp (jmp_buf buffer); +__attribute__((noreturn)) void longjmp(jmp_buf buffer, int value); + +// The NanoShell names for the functions (they're the same) +__attribute__((returns_twice)) int SetJump (JumpBuffer env); +__attribute__((noreturn)) void LongJump(JumpBuffer env, int value); + +#endif//_SETJMP___H \ No newline at end of file diff --git a/crt2/include/stdalign.h b/crt2/include/stdalign.h new file mode 100644 index 00000000..b2e53a44 --- /dev/null +++ b/crt2/include/stdalign.h @@ -0,0 +1,10 @@ +#ifndef _STDALIGN_H +#define _STDALIGN_H 1 + +#define alignas _Alignas +#define alignof _Alignof + +#define __alignas_is_defined 1 +#define __alignof_is_defined 1 + +#endif diff --git a/crt2/include/stdarg.h b/crt2/include/stdarg.h new file mode 100644 index 00000000..fa243e0b --- /dev/null +++ b/crt2/include/stdarg.h @@ -0,0 +1,11 @@ +#ifndef _STDARG_H +#define _STDARG_H 1 + +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) + +#endif diff --git a/crt2/include/stdbool.h b/crt2/include/stdbool.h new file mode 100644 index 00000000..bb2328c1 --- /dev/null +++ b/crt2/include/stdbool.h @@ -0,0 +1,11 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H 1 + +#define bool _Bool + +#define true 1 +#define false 0 + +#define __bool_true_false_are_defined 1 + +#endif diff --git a/crt2/include/stddef.h b/crt2/include/stddef.h new file mode 100644 index 00000000..4b85c130 --- /dev/null +++ b/crt2/include/stddef.h @@ -0,0 +1,16 @@ +#ifndef _STDDEF_H +#define _STDDEF_H 1 + +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __WCHAR_TYPE__ wchar_t; + +#ifdef NULL +#undef NULL +#endif + +#define NULL ((void *)0) + +#define offsetof(s, m) __builtin_offsetof(s, m) + +#endif diff --git a/crt2/include/stdint.h b/crt2/include/stdint.h new file mode 100644 index 00000000..5f977daf --- /dev/null +++ b/crt2/include/stdint.h @@ -0,0 +1,107 @@ +#ifndef _STDINT_H +#define _STDINT_H 1 + +typedef __UINT8_TYPE__ uint8_t; +typedef __UINT16_TYPE__ uint16_t; +typedef __UINT32_TYPE__ uint32_t; +typedef __UINT64_TYPE__ uint64_t; + +typedef __UINT_LEAST8_TYPE__ uint_least8_t; +typedef __UINT_LEAST16_TYPE__ uint_least16_t; +typedef __UINT_LEAST32_TYPE__ uint_least32_t; +typedef __UINT_LEAST64_TYPE__ uint_least64_t; + +typedef __UINT_FAST8_TYPE__ uint_fast8_t; +typedef __UINT_FAST16_TYPE__ uint_fast16_t; +typedef __UINT_FAST32_TYPE__ uint_fast32_t; +typedef __UINT_FAST64_TYPE__ uint_fast64_t; + +typedef __INT8_TYPE__ int8_t; +typedef __INT16_TYPE__ int16_t; +typedef __INT32_TYPE__ int32_t; +typedef __INT64_TYPE__ int64_t; + +typedef __INT_LEAST8_TYPE__ int_least8_t; +typedef __INT_LEAST16_TYPE__ int_least16_t; +typedef __INT_LEAST32_TYPE__ int_least32_t; +typedef __INT_LEAST64_TYPE__ int_least64_t; + +typedef __INT_FAST8_TYPE__ int_fast8_t; +typedef __INT_FAST16_TYPE__ int_fast16_t; +typedef __INT_FAST32_TYPE__ int_fast32_t; +typedef __INT_FAST64_TYPE__ int_fast64_t; + +typedef __UINTPTR_TYPE__ uintptr_t; +typedef __INTPTR_TYPE__ intptr_t; + +typedef __UINTMAX_TYPE__ uintmax_t; +typedef __INTMAX_TYPE__ intmax_t; + +#define UINT8_MAX __UINT8_MAX__ +#define UINT16_MAX __UINT16_MAX__ +#define UINT32_MAX __UINT32_MAX__ +#define UINT64_MAX __UINT64_MAX__ + +#define INT8_MAX __INT8_MAX__ +#define INT16_MAX __INT16_MAX__ +#define INT32_MAX __INT32_MAX__ +#define INT64_MAX __INT64_MAX__ + +#define INT8_MIN (-INT8_MAX - 1) +#define INT16_MIN (-INT16_MAX - 1) +#define INT32_MIN (-INT32_MAX - 1) +#define INT64_MIN (-INT64_MAX - 1) + +#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__ +#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__ +#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__ +#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__ + +#define INT_LEAST8_MAX __INT_LEAST8_MAX__ +#define INT_LEAST16_MAX __INT_LEAST16_MAX__ +#define INT_LEAST32_MAX __INT_LEAST32_MAX__ +#define INT_LEAST64_MAX __INT_LEAST64_MAX__ + +#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1) +#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1) +#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1) +#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1) + +#define UINT_FAST8_MAX __UINT_FAST8_MAX__ +#define UINT_FAST16_MAX __UINT_FAST16_MAX__ +#define UINT_FAST32_MAX __UINT_FAST32_MAX__ +#define UINT_FAST64_MAX __UINT_FAST64_MAX__ + +#define INT_FAST8_MAX __INT_FAST8_MAX__ +#define INT_FAST16_MAX __INT_FAST16_MAX__ +#define INT_FAST32_MAX __INT_FAST32_MAX__ +#define INT_FAST64_MAX __INT_FAST64_MAX__ + +#define INT_FAST8_MIN (-INT_FAST8_MAX - 1) +#define INT_FAST16_MIN (-INT_FAST16_MAX - 1) +#define INT_FAST32_MIN (-INT_FAST32_MAX - 1) +#define INT_FAST64_MIN (-INT_FAST64_MAX - 1) + +#define UINTPTR_MAX __UINTPTR_MAX__ +#define INTPTR_MAX __INTPTR_MAX__ +#define INTPTR_MIN (-INTPTR_MAX - 1) + +#define UINTMAX_MAX __UINTMAX_MAX__ +#define INTMAX_MAX __INTMAX_MAX__ +#define INTMAX_MIN (-INTMAX_MAX - 1) + +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define PTRDIFF_MIN (-PTRDIFF_MAX - 1) + +#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ +#define SIG_ATOMIC_MIN (-SIG_ATOMIC_MAX - 1) + +#define SIZE_MAX __SIZE_MAX__ + +#define WCHAR_MAX __WCHAR_MAX__ +#define WCHAR_MIN (-WCHAR_MAX - 1) + +#define WINT_MAX __WINT_MAX__ +#define WINT_MIN (-WINT_MAX - 1) + +#endif diff --git a/crt2/include/stdio.h b/crt2/include/stdio.h new file mode 100644 index 00000000..607f6f0c --- /dev/null +++ b/crt2/include/stdio.h @@ -0,0 +1,59 @@ +// stdio.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _STDIO__H +#define _STDIO__H + +#include + +// Standard C file access functions + +FILE* fopen (const char* file, const char* mode); +FILE* fdopen(int fd, const char* mode); +int fclose(FILE* file); +int fread ( void* ptr, size_t size, size_t nmemb, FILE* stream); +int fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream); +int fseek (FILE* file, int offset, int whence); +int ftell (FILE* file); +int fflush(FILE* file); +int fputs (const char* s, FILE* stream); +int fputc (int c, FILE* stream); +int putc (int c, FILE* stream); +int feof (FILE* file); +int getc (FILE* file); +void rewind(FILE* file); +int vfprintf (FILE* file, const char* fmt, va_list list); +int fprintf (FILE* file, const char* fmt, ...); +int vprintf (const char* fmt, va_list list); + +// Operations on files +int remove(const char* filename); +int rename(const char* oldname, const char* newname); +int renameat(int olddirdd, const char* oldname, int newdirdd, const char* newname); + +// External definitions to stdin, stdout and stderr +extern FILE *stdin, *stdout, *stderr; + +// Formatted input/output +int vfprintf(FILE* file, const char* fmt, va_list list); +int fprintf (FILE* file, const char* fmt, ...); +int vsnprintf(char* OutBuffer, size_t BufferSize, const char* FormatType, va_list list); +int vsprintf (char* OutBuffer, const char* FormatType, va_list list); +int snprintf (char* OutBuffer, size_t BufferSize, const char* fmt, ...); +int sprintf (char* OutBuffer, const char* FormatType, ...); +void LogMsg (const char* Format, ...); +void LogMsgNoCr(const char* Format, ...); +int printf (const char* Format, ...); + +// Character input/output +int fputs(const char* s, FILE * stream); +int fputc(int c, FILE * stream); +int putc(int c, FILE* stream); +int puts(const char * s); +int putchar(int c); +int fgetc(FILE* stream); +int getc(FILE* stream); +int ungetc(int c, FILE * stream); +int ferror(FILE* stream); + +#endif//_STDIO__H \ No newline at end of file diff --git a/crt2/include/stdlib.h b/crt2/include/stdlib.h new file mode 100644 index 00000000..aa122cd5 --- /dev/null +++ b/crt2/include/stdlib.h @@ -0,0 +1,63 @@ +// stdlib.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _STDLIB__H +#define _STDLIB__H + +#include +#include +#include + +// Numeric conversion functions +long long atoll (const char* str); +int atoi (const char* str); +int atox (const char* str); +long atol (const char* str); +double atof (const char *arr); +char* itoa (int value, char* buffer, int radix); +char* ltoa (long value, char* buffer, int radix); + +// Memory management +void* malloc (size_t size); +void* calloc (size_t nmemb, size_t size); +void free (void* ptr); +void* realloc(void* ptr, size_t sz); + +// Arithmetic utilities +int abs(int k); +double fabs(double x); + +// Random number generator +int GetRandom(void); // use the kernel RNG +int rand(void); +int rand_r(unsigned int * seed); +void srand(unsigned int seed); + +// Communication with the environment +__attribute__((noreturn)) void exit(int status); +__attribute__((noreturn)) void abort(void); +//TODO: atexit +//TODO: getenv +//TODO: system + +// Sorting functions +// NOTE: I'd prefer you don't use these right now. They're just bubble sort. I'll implement a smarter sorting algorithm later on. +void qsort(void *pBase, size_t nCount, size_t nElementSize, ComparisonFunc pCompare); +void qsort_r(void *pBase, size_t nCount, size_t nElementSize, ComparisonReentrantFunc pCompareReentrant, void* pArgument); + +// Environment +char* getenv(const char* name); + +// Safe string conversion +unsigned long long strtoux(const char* str, char ** endptr, int base, unsigned long long max); +long long strtox(const char* str, char ** endptr, int base, long long max); +unsigned long long int strtoull(const char* str, char ** endptr, int base); +unsigned long int strtoul(const char* str, char ** endptr, int base); +long long int strtoll(const char* str, char ** endptr, int base); +long int strtol(const char* str, char ** endptr, int base); +double ldexp(double val, int exp); +double strtod(const char* str, char** endptr); +long double strtold(const char* str, char** endptr); +float strtof(const char* str, char** endptr); + +#endif//_STDLIB__H diff --git a/crt2/include/stdnoreturn.h b/crt2/include/stdnoreturn.h new file mode 100644 index 00000000..9c2691f4 --- /dev/null +++ b/crt2/include/stdnoreturn.h @@ -0,0 +1,6 @@ +#ifndef _STDNORETURN_H +#define _STDNORETURN_H 1 + +#define noreturn _Noreturn + +#endif diff --git a/crt2/include/string.h b/crt2/include/string.h new file mode 100644 index 00000000..510c831f --- /dev/null +++ b/crt2/include/string.h @@ -0,0 +1,39 @@ +// string.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _STRING__H +#define _STRING__H + +#include + +int memcmp (const void* s1, const void* s2, size_t n); +void* memcpy (void* dest, const void* src, size_t n); +void* memmove (void* dest, const void* src, size_t n); +void* memset (void* s, int c, size_t n); +size_t strlen (const char* s); +char* strcpy (char *dest, const char* src); +char* strncpy (char *dest, const char *src, size_t n); +size_t strlcpy (char *dest, const char *src, size_t n); +int strcmp (const char* as, const char* bs); +int strncmp (const char* s1, const char* s2, size_t n); +char* strcat (char* dest, const char* after); +void strtolower (char* as); +void strtoupper (char* as); +void memtolower (char* as, int w); +void memtoupper (char* as, int w); +size_t strgetlento(const char* str, char chr); +char* strdup (const char *pText); +char* strstr (const char *haystack, const char *needle); +size_t strnlen (const char* str, size_t szmax); +char* strchr (const char* s, int c); +char* strrchr (const char* s, int c); +char* strchrnul (const char* s, int c); // GNU extension +size_t strspn (const char* s, const char* accept); +size_t strcspn (const char* s, const char* reject); +void* memchr (const void* s, int c, size_t n); +void* memrchr (const void* s, int c, size_t n); +void* rawmemchr (const void* s, int c); + +const char * strerror (int errnum); + +#endif//_STRING__H diff --git a/crt2/include/sys/mman.h b/crt2/include/sys/mman.h new file mode 100644 index 00000000..79084517 --- /dev/null +++ b/crt2/include/sys/mman.h @@ -0,0 +1,12 @@ +// sys/mman.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __SYS__MMAN_H +#define __SYS__MMAN_H + +#include + +void* mmap(void *, size_t, int, int, int, off_t); +int munmap(void *, size_t); + +#endif//__SYS__MMAN_H \ No newline at end of file diff --git a/crt2/include/sys/time.h b/crt2/include/sys/time.h new file mode 100644 index 00000000..647ffe63 --- /dev/null +++ b/crt2/include/sys/time.h @@ -0,0 +1,9 @@ +// sys/time.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __SYS_TIME_H +#define __SYS_TIME_H + +//TODO + +#endif//__SYS_TIME_H \ No newline at end of file diff --git a/crt2/include/sys/types.h b/crt2/include/sys/types.h new file mode 100644 index 00000000..c07dfe3d --- /dev/null +++ b/crt2/include/sys/types.h @@ -0,0 +1,25 @@ +// sys/types.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef __SYS__TYPES_H +#define __SYS__TYPES_H + +#include +#include +#include +#include + +typedef long mode_t; +typedef long nlink_t; +typedef long uid_t; +typedef long gid_t; +typedef long id_t; +typedef long pid_t; +typedef long tid_t; +typedef long blkcnt_t; +typedef long off_t; +typedef unsigned long fsblkcnt_t; +typedef unsigned long fsfilcnt_t; +typedef unsigned long ino_t; + +#endif//__SYS__TYPES_H \ No newline at end of file diff --git a/crt2/include/time.h b/crt2/include/time.h new file mode 100644 index 00000000..5385240f --- /dev/null +++ b/crt2/include/time.h @@ -0,0 +1,22 @@ +// time.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _TIME___H +#define _TIME___H + +#include + +double difftime(time_t a, time_t b); +time_t time(time_t* timer); +time_t mktime (struct tm * ptr); +struct tm* localtime_r(const time_t* timep, struct tm * result); +struct tm* localtime(const time_t* timep); + +// NanoShell specifics +void StructTmToTimeStruct(TimeStruct* out, struct tm* in); +void TimeStructToStructTm(TimeStruct* in, struct tm* out); +int GetEpochTimeFromTimeStruct(TimeStruct* ts); +int GetEpochTime(); +void GetHumanTimeFromEpoch(int utime, TimeStruct* pOut); + +#endif//_TIME___H diff --git a/crt2/include/unistd.h b/crt2/include/unistd.h new file mode 100644 index 00000000..7fb5082d --- /dev/null +++ b/crt2/include/unistd.h @@ -0,0 +1,18 @@ +// unistd.h +// Copyright (C) 2022 iProgramInCpp +// The NanoShell Standard C Library +#ifndef _UNISTD_H +#define _UNISTD_H + +#include + +// POSIX file access functions +int open (const char* path, int oflag); +int close (int fd); +int read (int fd, void* buf, unsigned int nbyte); +int write (int fd, const void* buf, unsigned int nbyte); +int lseek (int fd, int offset, int whence); +int tellf (int fd); +int tellsz(int fd); + +#endif//_UNISTD_H \ No newline at end of file diff --git a/crt2/lib_i386.ld b/crt2/lib_i386.ld new file mode 100644 index 00000000..f901b493 --- /dev/null +++ b/crt2/lib_i386.ld @@ -0,0 +1,3 @@ +/* Tell the linker that we want an ELF32 output file */ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) diff --git a/crt2/src/a_assert.c b/crt2/src/a_assert.c new file mode 100644 index 00000000..1a52480b --- /dev/null +++ b/crt2/src/a_assert.c @@ -0,0 +1,28 @@ +// *************************************************************** +// a_assert.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +__attribute__((noreturn)) +void abort() +{ + // TODO + *((uint32_t*)0xFFFFFFF4) = 0xFFFFFFFF; + while (true); +} + +void OnAssertionFail(const char *cond_msg, const char *file, int line) +{ + LogMsg("ASSERTION FAILED!"); + LogMsg("The assertion \"%s\" failed at %s:%d.", cond_msg, file, line); + LogMsg("The program will now exit."); + abort(); +} diff --git a/crt2/src/a_cc.c b/crt2/src/a_cc.c new file mode 100644 index 00000000..77ffffd3 --- /dev/null +++ b/crt2/src/a_cc.c @@ -0,0 +1,17 @@ +// *************************************************************** +// a_cc.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +int CcRunCCode(const char* data, int length) +{ + return _I_CcRunCCode (data, length); +} diff --git a/crt2/src/a_env.c b/crt2/src/a_env.c new file mode 100644 index 00000000..751084dd --- /dev/null +++ b/crt2/src/a_env.c @@ -0,0 +1,18 @@ +// *************************************************************** +// a_env.c - Creation date: 29/12/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +char* getenv(UNUSED const char* name) +{ + // TODO: Call into the system and grab info from ns.ini. + return NULL; +} diff --git a/crt2/src/a_error.c b/crt2/src/a_error.c new file mode 100644 index 00000000..4920bfcb --- /dev/null +++ b/crt2/src/a_error.c @@ -0,0 +1,57 @@ +// *************************************************************** +// a_error.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +// note: The error number is stored as positive. +int g_errorNum = 0; + +static __attribute__((always_inline)) +int absolute_value(int a) +{ + return a < 0 ? -a : a; +} + +int SetErrorNumber(int err) +{ + g_errorNum = absolute_value(err); + return -1; +} + +int* GetErrorNumberPointer() +{ + return &g_errorNum; +} + +int GetErrorNumber() +{ + return g_errorNum; +} + +const char* strerror(int errnum) +{ + return ErrNoStr(-errnum); +} + +int seterrno(int en) +{ + return g_errorNum = absolute_value(en); +} + +int geterrno() +{ + return g_errorNum; +} + +int* geterrnoptr() +{ + return &g_errorNum; +} diff --git a/crt2/src/a_file.c b/crt2/src/a_file.c new file mode 100644 index 00000000..408c4422 --- /dev/null +++ b/crt2/src/a_file.c @@ -0,0 +1,829 @@ +// *************************************************************** +// a_file.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +// Max files open at once -- increase if necessary +#define FD_STDIO 65535 +#define FIMAX 64 +#define EOT 4 // end of transmission, aka Ctrl-D + +static int g_OpenedFileDes[FIMAX]; +static int g_OpenedDirDes [FIMAX]; + +static int FileSpotToFileHandle(int spot) +{ + if (spot < 0 || spot >= FIMAX) return -1; + return g_OpenedFileDes[spot]; +} + +static int DirSpotToFileHandle(int spot) +{ + if (spot < 0 || spot >= FIMAX) return -1; + return g_OpenedDirDes[spot]; +} + +// Check if a file is opened here in this process +bool _I_IsFileOpenedHere(int fd) +{ + for (int i = 0; i < FIMAX; i++) + { + if (g_OpenedFileDes[i] == fd) + return true; + } + return false; +} + +// Check if a directory is opened here in this process +bool _I_IsDirectoryOpenedHere(int dd) +{ + for (int i = 0; i < FIMAX; i++) + { + if (g_OpenedDirDes[i] == dd) + return true; + } + return false; +} + +int open(const char* path, int oflag) +{ + int spot = -1; + + for (int i = 0; i < FIMAX; i++) + { + if (g_OpenedFileDes[i] < 0) + { + spot = i; break; + } + } + + if (spot == -1) + { + SetErrorNumber(-EMFILE); + return -1; + } + + // FiOpenDebug now supports custom paths... + int fd = _I_FiOpenDebug(path, oflag, "usertask", 1); + + if (fd < 0) + { + SetErrorNumber(fd); + return -1; + } + + g_OpenedFileDes[spot] = fd; + return spot; +} + +int close(int spot) +{ + int fd = FileSpotToFileHandle(spot); + if (fd < 0) + { + SetErrorNumber(-EBADF); + return -1; + } + + if (!_I_IsFileOpenedHere(fd)) + { + SetErrorNumber(-EBADF); + return -1; + } + + int rv = _I_FiClose (fd); + + // if closing was successful: + if (rv >= 0) + { + g_OpenedFileDes[spot] = -1; + } + + return rv; +} + +// honestly, this needs to be redone too +int read_stdio(void* buf, unsigned int nbyte) +{ + char* bufchar = buf; + for (unsigned i = 0; i < nbyte; i++) + { + char c = _I_ReadChar(); + *(bufchar++) = c; + + // If we got an 'end of transmission', instantly return + if (c == EOT) + return (int)i; + } + + return nbyte; +} + +int write_stdio(const void* buf, unsigned int nbyte) +{ + const char* bufchar = buf; + char b[2]; + b[1] = 0; + for (unsigned i = 0; i < nbyte; i++) + { + b[0] = *(bufchar++); + _I_PutString(b); + } + + return nbyte; +} + +int read(int spot, void* buf, unsigned int nbyte) +{ + int filedes = FileSpotToFileHandle(spot); + if (filedes < 0) + return SetErrorNumber(-EBADF); + + if (!_I_IsFileOpenedHere(filedes)) + return SetErrorNumber(-EBADF); + + if (filedes == FD_STDIO) + { + return read_stdio(buf, nbyte); + } + + int result = _I_FiRead(filedes, buf, nbyte); + + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int write(int spot, const void* buf, unsigned int nbyte) +{ + int filedes = FileSpotToFileHandle(spot); + if (filedes < 0) + return SetErrorNumber(-EBADF); + + if (!_I_IsFileOpenedHere(filedes)) + return SetErrorNumber(-EBADF); + + if (filedes == FD_STDIO) + { + return write_stdio(buf, nbyte); + } + + int result = _I_FiWrite(filedes, (void*)buf, nbyte); + + if (result < 0) + return SetErrorNumber((int)result); + + return result; +} + +int lseek(int spot, int offset, int whence) +{ + int filedes = FileSpotToFileHandle(spot); + if (filedes < 0) + return SetErrorNumber(-EBADF); + + if (filedes == FD_STDIO) return SetErrorNumber(-ESPIPE); + + if (!_I_IsFileOpenedHere(filedes)) + return SetErrorNumber(-EBADF); + + int result = _I_FiSeek(filedes, offset, whence); + + if (result < 0) + return SetErrorNumber((int)result); + + return result; +} + +int tellf(int spot) +{ + int filedes = FileSpotToFileHandle(spot); + if (filedes < 0) + return SetErrorNumber(-EBADF); + + if (filedes == FD_STDIO) return SetErrorNumber(-ESPIPE); + + if (!_I_IsFileOpenedHere(filedes)) + return SetErrorNumber(-EBADF); + + int result = _I_FiTell(filedes); + + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int tellsz(int spot) +{ + int filedes = FileSpotToFileHandle(spot); + if (filedes < 0) + return SetErrorNumber(-EBADF); + + if (filedes == FD_STDIO) return SetErrorNumber(-ESPIPE); + + if (!_I_IsFileOpenedHere(filedes)) + return SetErrorNumber(-EBADF); + + int result = _I_FiTellSize(filedes); + + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int ioctl(int spot, unsigned long request, void * argp) +{ + int filedes = FileSpotToFileHandle(spot); + if (filedes < 0) + return SetErrorNumber(-EBADF); + + if (filedes == FD_STDIO) + { + // process the IO request directly TODO + return -ENOTTY; + } + + if (!_I_IsFileOpenedHere(filedes)) + return SetErrorNumber(-EBADF); + + int result = _I_FiIoControl(filedes, request, argp); + + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int FiOpenDir(const char* pFileName) +{ + int spot = -1; + + for (int i = 0; i < FIMAX; i++) + { + if (g_OpenedFileDes[i] < 0) + { + spot = i; break; + } + } + + if (spot == -1) + { + SetErrorNumber(-EMFILE); + return -EMFILE; + } + + int fd = _I_FiOpenDirD(pFileName, "[Process]", 1); + + if (fd < 0) + return SetErrorNumber(fd); + + g_OpenedDirDes[spot] = fd; + + return spot; +} + +int FiCloseDir(int spot) +{ + int dd = DirSpotToFileHandle(spot); + if (dd < 0) + return SetErrorNumber(-EBADF); + + if (!_I_IsDirectoryOpenedHere(dd)) + return SetErrorNumber(-EBADF); + + int closeRes = _I_FiCloseDir(dd); + if (closeRes >= 0) + { + for (int i = 0; i < FIMAX; i++) + { + if (g_OpenedDirDes[i] == dd) + g_OpenedDirDes[i] = -1; + } + } + else + return SetErrorNumber(closeRes); + + return closeRes; +} + +int FiReadDir(DirEnt* space, int spot) +{ + int dd = DirSpotToFileHandle(spot); + if (dd < 0) + { + SetErrorNumber(-EBADF); + return -1; + } + + if (!_I_IsDirectoryOpenedHere(dd)) + { + SetErrorNumber(-EBADF); + return -1; + } + + int result = _I_FiReadDir(space, dd); + + if (result >= 0) + return result; + + SetErrorNumber(result); + return -1; +} + +int FiSeekDir(int spot, int loc) +{ + int dd = DirSpotToFileHandle(spot); + if (dd < 0) + return SetErrorNumber(-EBADF); + + if (!_I_IsDirectoryOpenedHere(dd)) + return SetErrorNumber(-EBADF); + + int result = _I_FiSeekDir(dd, loc); + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int FiRewindDir(int spot) +{ + int dd = DirSpotToFileHandle(spot); + if (dd < 0) + return SetErrorNumber(-EBADF); + + if (!_I_IsDirectoryOpenedHere(dd)) + return SetErrorNumber(-EBADF); + + int result = _I_FiRewindDir(dd); + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int FiTellDir(int spot) +{ + int dd = DirSpotToFileHandle(spot); + if (dd < 0) + return SetErrorNumber(-EBADF); + + if (!_I_IsDirectoryOpenedHere(dd)) + return SetErrorNumber(-EBADF); + + int result = _I_FiTellDir(dd); + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int FiStatAt(int spot, const char *pfn, StatResult* pres) +{ + int dd = DirSpotToFileHandle(spot); + if (dd < 0) + return SetErrorNumber(-EBADF); + + if (!_I_IsDirectoryOpenedHere(dd)) + return SetErrorNumber(-EBADF); + + int result = _I_FiStatAt(dd, pfn, pres); + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int FiStat(const char *pfn, StatResult* pres) +{ + int result = _I_FiStat(pfn, pres); + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int FiLinkStat(const char *pfn, StatResult* pres) +{ + int result = _I_FiLinkStat(pfn, pres); + if (result < 0) + return SetErrorNumber(result); + + return result; +} + +int FiChDir(const char *pfn) +{ + int result = _I_FiChDir(pfn); + if (result < 0) + SetErrorNumber(result); + + return result; +} + +// C Standard I/O +FILE* fdopen (int fd, UNUSED const char* type) +{ + if (fd < 0) + return NULL; + + FILE* pFile = calloc(1, sizeof(FILE)); + if (!pFile) + { + close(fd); + return NULL; + } + pFile->fd = fd; + return pFile; +} + +FILE* fopen (const char* file, const char* mode) +{ + const char* mode1 = mode; + int flags = O_CREAT; + + while (*mode) + { + switch (*mode) + { + case'r':case'R':flags |= O_RDONLY;break; + case'w':case'W':flags |= O_WRONLY;break; + case'a':case'A':flags |= O_APPEND;break; + case'+': flags &=~O_CREAT; break; + } + mode++; + } + + return fdopen(open(file, flags), mode1); +} + +int fclose(FILE* file) +{ + if (file->fd == FD_STDIO) return SetErrorNumber(-ESPIPE); + + if (file) + { + int op = close(file->fd); + + if (op < 0) + { + SetErrorNumber(op); + return op; + } + + free (file); + return op; + } + + SetErrorNumber(-EBADF); + return -EBADF; +} + +size_t fread (void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + SetErrorNumber(0); + + size_t nbyte = size * nmemb; + size_t rd = read(stream->fd, ptr, nbyte); + + if (rd < nbyte) + { + // must have reached end of file + stream->eof = true; + } + + if (GetErrorNumber()) + { + stream->error = true; + } + + return rd; +} + +size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + SetErrorNumber(0); + + size_t nbyte = size * nmemb; + size_t wr = write(stream->fd, ptr, nbyte); + if (wr < nbyte) + { + stream->eof = true; + } + + if (GetErrorNumber()) + { + stream->error = true; + } + + return wr; +} + +int fseek(FILE* file, int offset, int whence) +{ + SetErrorNumber(0); + int rv = lseek(file->fd, offset, whence); + + if (GetErrorNumber()) + { + file->error = true; + } + + return rv; +} + +int ftell(FILE* file) +{ + SetErrorNumber(0); + int rv = tellf(file->fd); + + if (GetErrorNumber()) + { + file->error = true; + } + + return rv; +} + +void rewind(FILE* stream) +{ + fseek(stream, 0, SEEK_SET); +} + +// called on exit +void _I_CloseOpenFiles() +{ + for (int i = 0; i < FIMAX; i++) + { + if (g_OpenedFileDes[i] >= 0) + { + _I_FiClose(g_OpenedFileDes[i]); + g_OpenedFileDes[i] = -1; + } + } +} + +FILE *stdin, *stdout, *stderr; + +// called on start +void _I_Setup() +{ + for (int i = 0; i < FIMAX; i++) + g_OpenedFileDes[i] = g_OpenedDirDes[i] = -1; + + g_OpenedFileDes[0] = FD_STDIO; + g_OpenedFileDes[1] = FD_STDIO; + g_OpenedFileDes[2] = FD_STDIO; + + //well, they're going to be the same file, which is fine. + //Points to file description 0, which is handle FD_STDIO, should be ok. + stdin = stdout = stderr = calloc(1, sizeof(FILE)); + stdin->fd = 0; +} + +int unlink (const char* filename) +{ + return _I_FiUnlinkFile(filename); +} + +int getc (FILE* pFile) +{ + if (pFile->ungetc_buf_sz > 0) + { + return pFile->ungetc_buf[--pFile->ungetc_buf_sz]; + } + + char chr = 0; + fread(&chr, 1, 1, pFile); + if (pFile->eof) + return EOF; + + return chr; +} + +int fgetc(FILE* stream) +{ + return getc(stream); +} + +int ungetc(int c, FILE * stream) +{ + if (stream->ungetc_buf_sz >= (int) sizeof stream->ungetc_buf) + return EOF; + + stream->ungetc_buf[stream->ungetc_buf_sz++] = c; + return 0; +} + +int feof(FILE* f) +{ + return f->eof; +} + +int ferror(FILE* f) +{ + return f->error; +} + +void clearerr(FILE* f) +{ + f->error = 0; +} + +// empty for now. There's no actual flushing to be done. +int fflush(FILE* file) +{ + (void)file; + return 0; +} + +int rename(const char* old, const char* new) +{ + return _I_FiRename(old, new); +} + +int renameat(int olddirspot, const char* old, int newdirspot, const char* new) +{ + //TODO + (void) old; (void) new; + (void) olddirspot; (void) newdirspot; + return -ENOTSUP; +} + +int mkdir(const char * path, UNUSED int mode) +{ + return _I_FiMakeDir(path); +} + +int rmdir(const char * path) +{ + return _I_FiRemoveDir(path); +} + +int FiCreatePipe(const char * friendlyName, int pipefd[2], int flags) +{ + // look for two free spots. + int j = 0; + for (int i = 0; i < FIMAX && j < 2; i++) + { + if (g_OpenedFileDes[i] == -1) + pipefd[j++] = i; + } + + // if j didn't reach 2.. + if (j < 2) + { + //we have too many files open + return -EMFILE; + } + + int kshandles[2]; + int result = _I_FiCreatePipe(friendlyName, kshandles, flags); + + if (result < 0) return result; // actually don't do anything + + // assign the two pipefd's to the kernel handles + g_OpenedFileDes[pipefd[0]] = kshandles[0]; + g_OpenedFileDes[pipefd[1]] = kshandles[1]; + + return 0; +} + +int pipe2(int pipefd[2], int flags) +{ + return FiCreatePipe("pipe", pipefd, flags); +} + +int pipe(int pipefd[2]) +{ + return pipe2(pipefd, 0); +} + +int remove (const char* filename) +{ + StatResult res; + int stat = FiStat(filename, &res); + if (stat < 0) return stat; + + if (res.m_type == FILE_TYPE_DIRECTORY) + { + return _I_FiRemoveDir(filename); + } + else + { + return _I_FiUnlinkFile(filename); + } +} + +void* mmap(void * addr, size_t length, int prot, int flags, int fd, off_t offset) +{ + void* pMem = MAP_FAILED; + + int ec = MemoryMap(addr, length, prot, flags, fd, offset, &pMem); + + if (ec < 0) + { + SetErrorNumber(ec); + return MAP_FAILED; + } + + return pMem; +} + +int munmap(void * addr, size_t sz) +{ + int ec = MemoryUnmap(addr, sz); + if (ec < 0) + SetErrorNumber(ec); + return ec; +} + +char* getcwd(char* buf, size_t sz) +{ + strncpy(buf, FiGetCwd(), sz); + buf[sz - 1] = 0; + return buf; +} + +// Standard C wrappers for directory ops +DIR* opendir(const char* dirname) +{ + int dd = FiOpenDir(dirname); + if (dd < 0) + return NULL; // errno is already set + + DIR* dir = malloc(sizeof(DIR)); + dir->m_DirHandle = dd; + return dir; +} + +int closedir(DIR* dirp) +{ + int result = FiCloseDir(dirp->m_DirHandle); + if (result < 0) + return -1; + + free(dirp); + return 0; +} + +void rewinddir(DIR* dirp) +{ + // seek to the beginning, ie. 0 + FiSeekDir(dirp->m_DirHandle, 0); +} + +int telldir(DIR* dirp) +{ + return FiTellDir(dirp->m_DirHandle); +} + +void seekdir(DIR* dirp, int told) +{ + FiSeekDir(dirp->m_DirHandle, told); +} + +struct dirent* readdir(DIR* dirp) +{ + // keep an offset that we can fill in. + int offset = FiTellDir(dirp->m_DirHandle); + + // if we couldn't grab the telldir result, just bail. FiTellDir set an errno anyways + if (offset < 0) + return NULL; + + // note: It doesn't matter if we skip some entries (. and ..), those will be + // skipped again if we seekdir() to dirent->d_off and readdir() again. + + // perform the actual read + int result = FiReadDir(&dirp->m_NDirEnt, dirp->m_DirHandle); + + // if we got nothing (i.e. either hit the end, or had an error), + // return null. FiReadDir sets an errno if something happened. + if (result != 0) + return NULL; + + // fill out the entries here: + DirEnt* pDirEnt = &dirp->m_NDirEnt; + struct dirent* ptr = &dirp->m_PDirEnt; // posix dirent + + strcpy(ptr->d_name, pDirEnt->m_name); + + ptr->d_reclen = sizeof(*ptr); + ptr->d_ino = pDirEnt->m_inode; + ptr->d_type = pDirEnt->m_type; + ptr->d_off = offset; + + return ptr; +} diff --git a/crt2/src/a_math.c b/crt2/src/a_math.c new file mode 100644 index 00000000..299db36a --- /dev/null +++ b/crt2/src/a_math.c @@ -0,0 +1,60 @@ +// *************************************************************** +// a_math.c - Creation date: 06/12/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +int abs (int a) +{ + if (a < 0) + return -a; + + return a; +} + +double fabs (double x) +{ + if (x < 0) + return -x; + + return x; +} + +static unsigned int s_randomSeed; + +void _I_RandInit() +{ + s_randomSeed = GetRandom(); +} + +// TODO: Replace this with a better RNG. +static unsigned int temper(unsigned int x) +{ + x ^= x >> 11; + x ^= x << 7 & 0x9d2c5680; + x ^= x << 15 & 0xefc60000; + x ^= x >> 18; + return x; +} + +int rand_r(unsigned int * seed) +{ + return (temper(*seed = *seed * 1103515245 + 12345) / 2) & 0x7FFFFFFF; +} + +int rand() +{ + return rand_r(&s_randomSeed); +} + +void srand(unsigned int seed) +{ + s_randomSeed = seed; +} diff --git a/crt2/src/a_mem.c b/crt2/src/a_mem.c new file mode 100644 index 00000000..7135643a --- /dev/null +++ b/crt2/src/a_mem.c @@ -0,0 +1,638 @@ +// *************************************************************** +// a_mem.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +void SLogMsg(const char * c, ...); +void SLogMsgNoCr(const char* fmt, ...); + +// If the free gap has between and + 32 bytes, don't split it. It's kind of a waste. +// If the free gap's size is + 32 bytes and over, proceed to perform a split. +#define C_MEM_ALLOC_TOLERANCE (32) + +// If a newly freed block of memory is larger than 1024 bytes, g_bAddedToLastHeaderHint gets set to +// false.. So new allocations would try that spot first. +#define C_MEM_FREE_LARGE_ENOUGH (4096) + +#define MAGIC_NUMBER_1_USED (0xDDEAFB10) +#define MAGIC_NUMBER_2_USED (0x19960623) +#define MAGIC_NUMBER_1_FREE (0x00000000) +#define MAGIC_NUMBER_2_FREE (0x534F534E) + +#define C_MEMORY_SIZE (0x40000000) // 1 GB. Should you need more, move gMemory down in memory (but avoid going below 0x10000000!!) + +// since MAGIC_NUMBER_1_FREE is zero +#define IS_FREE(header) (!((header)->m_magicNo1)) + +typedef struct MemAreaHeader +{ + uint32_t m_magicNo1; + struct MemAreaHeader* m_pNext; + struct MemAreaHeader* m_pPrev; + size_t m_size; + uint32_t m_magicNo2; +} +MemAreaHeader; + +#define SIZE_AND_LOCATION_PADDING (1 << 2) // 4 + +// The memory area. Prefer imitating old NanoShell's way of doing things. +uint8_t* gMemory = (uint8_t*)0x40000000; + +// The size of the memory area. +const uintptr_t gMemorySize = C_MEMORY_SIZE; + +// 262144 entries, so 512 KB. Not Bad. Stores the amount of memory allocations that use this page. +uint16_t gMemoryPageReference [C_MEMORY_SIZE / 4096]; + +MemAreaHeader *gLastHeader; + +// for optimization, add to the last header if we've been doing that +// Not sure that it optimizes that much actually.. only a 2ms gain at best +bool g_bAddedToLastHeaderHint = false; + +bool MemMgrIsPageUsed(uintptr_t page) +{ + return gMemoryPageReference[page] != 0; +} + +void MemOnOOM(int errCode, bool bUnmappingMemory); + +void MemMgrRequestMemMap(uintptr_t place, size_t size) +{ + void *redundant; + int errorCode = MemoryMap((void*)(place & ~0xFFF), size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, &redundant); + + if (errorCode != -ENOTHING) + { + MemOnOOM(errorCode, false); + } +} + +void MemMgrAbort() +{ + abort(); +} + +void MemMgrRequestMemUnMap(uintptr_t place, size_t size) +{ + __attribute__((unused)) int errorCode = + MemoryUnmap((void*)(place & ~0xFFF), size); +} + +// don't use this directly +void MemMgrAddReferenceToPage(uintptr_t page) +{ + gMemoryPageReference[page]++; +} + +// this also +void MemMgrRemoveReferenceToPage(uintptr_t page) +{ + if (gMemoryPageReference[page]-- == 0) + { + gMemoryPageReference[page] = 0; + LogMsg("Tried to free the same page twice? (%p)", page); + abort(); + } +} + +MemAreaHeader* MemMgrSetupMemoryRegion(MemAreaHeader* pHeader, size_t nSize) +{ + pHeader->m_magicNo1 = MAGIC_NUMBER_1_USED; + pHeader->m_magicNo2 = MAGIC_NUMBER_2_USED; + pHeader->m_size = nSize; + + MemAreaHeader* pNext = (MemAreaHeader*)((uint8_t*)pHeader + sizeof *pHeader + nSize); + pHeader->m_pNext = pNext; + pNext ->m_pPrev = pHeader; + pNext ->m_pNext = NULL; + + return pNext; +} + +MemAreaHeader* MemMgrGetInitialHeader() +{ + return (MemAreaHeader*)gMemory; +} + +void MemMgrPerformSanityChecks(MemAreaHeader* pHeader) +{ + // Perform an address check first - make sure we aren't performing any OOB accesses. + uint8_t* pHeaderBytes = (uint8_t*)pHeader; + if (gMemory + gMemorySize <= pHeaderBytes || pHeaderBytes < gMemory) + { + LogMsg("Heap corruption detected! Block %p isn't within the memory area reserved to the program.", pHeader); + MemMgrAbort(); + } + + // Perform a magic number check + if ((pHeader->m_magicNo1 != MAGIC_NUMBER_1_FREE && pHeader->m_magicNo1 != MAGIC_NUMBER_1_USED) || + (pHeader->m_magicNo2 != MAGIC_NUMBER_2_FREE && pHeader->m_magicNo2 != MAGIC_NUMBER_2_USED)) + { + // Uh oh! We have a heap corruption. Report to the user! + LogMsg("Heap corruption detected! Block %p's magic numbers aren't correctly set.", pHeader); + MemMgrAbort(); + } + + // Yep, all good +} + +void MemMgrUseMemoryRegion(void* ptr, size_t sz) +{ + uintptr_t p = (uintptr_t) ptr - (uintptr_t) gMemory; + uintptr_t pageStart = p / 0x1000, pageEnd = (p + sz) / 0x1000; + uintptr_t mmapStreak = 0, pageStartedStreak = 0; + + for (uintptr_t page = pageStart; page <= pageEnd; page++) + { + //if the page isn't used, add to the current streak + if (!MemMgrIsPageUsed(page)) + { + if (mmapStreak++ == 0) + pageStartedStreak = page; + } + //well, it's used, so commit the current changes if we have a streak + else if (mmapStreak) + { + uintptr_t mmapCur = pageStartedStreak * 0x1000 + (uintptr_t) gMemory; + MemMgrRequestMemMap(mmapCur, mmapStreak * 4096); + mmapStreak = 0; + } + MemMgrAddReferenceToPage(page); + } + + //well, in the end we might still have some streak left, so be sure to map that too. + if (mmapStreak) + { + if (!pageStartedStreak) + pageStartedStreak = pageStart; + + uintptr_t mmapCur = pageStartedStreak * 0x1000 + (uintptr_t) gMemory; + MemMgrRequestMemMap(mmapCur, mmapStreak * 4096); + mmapStreak = 0; + } +} + +void MemMgrFreeMemoryRegion(void* ptr, size_t sz) +{ + uintptr_t p = (uintptr_t) ptr - (uintptr_t) gMemory; + uintptr_t pageStart = p / 0x1000, pageEnd = (p + sz) / 0x1000; + uintptr_t mmapStreak = 0, pageStartedStreak = 0; + + for (uintptr_t page = pageStart; page <= pageEnd; page++) + { + //if the page isn't used, add to the current streak + if (!MemMgrIsPageUsed(page)) + { + if (mmapStreak++ == 0) + pageStartedStreak = page; + } + //well, it's used, so commit the current changes if we have a streak + else if (mmapStreak) + { + uintptr_t mmapCur = pageStartedStreak * 0x1000 + (uintptr_t) gMemory; + MemMgrRequestMemUnMap(mmapCur, mmapStreak); + mmapStreak = 0; + } + MemMgrRemoveReferenceToPage(page); + } + + //well, in the end we might still have some streak left, so be sure to unmap that too. + if (mmapStreak) + { + if (!pageStartedStreak) + pageStartedStreak = pageStart; + + uintptr_t mmapCur = pageStartedStreak * 0x1000 + (uintptr_t) gMemory; + MemMgrRequestMemUnMap(mmapCur, mmapStreak * 4096); + mmapStreak = 0; + } +} + +// Initialise the first block. +void MemMgrInitializeMemory() +{ + MemAreaHeader *pHeader = MemMgrGetInitialHeader(); + + MemMgrUseMemoryRegion(pHeader, sizeof (MemAreaHeader)); + gLastHeader = pHeader; + + pHeader->m_magicNo1 = MAGIC_NUMBER_1_FREE; + pHeader->m_magicNo2 = MAGIC_NUMBER_2_FREE; + pHeader->m_pNext = NULL; + pHeader->m_pPrev = NULL; + pHeader->m_size = gMemorySize - sizeof(MemAreaHeader); +} + +// First-fit allocation method. We could also use best-fit, however right now I'd rather not. +void* MemMgrAllocateMemory(size_t sz) +{ + if (sz == 0) + return NULL; + + // Pad the size to four bytes, or one double word. + sz = (sz + SIZE_AND_LOCATION_PADDING - 1) & ~(SIZE_AND_LOCATION_PADDING - 1); + + // TODO OPTIMIZE - Store a pointer to the biggest block that's free right now, or something else like that. + + // Okay, first off, navigate our linked list + MemAreaHeader* pHeader = MemMgrGetInitialHeader(), *pLastHeader = NULL; + + while (pHeader) + { + // Perform a sanity check first, before doing *anything*. Has its reasons. + MemMgrPerformSanityChecks(pHeader); + + // is this even free? + if (IS_FREE(pHeader)) + { + // yeah, simply check if we have a free slot here. + if (pHeader->m_size >= sz) + { + // This is good. Now, do we split this up? + if (pHeader->m_size >= sz + sizeof (MemAreaHeader) + C_MEM_ALLOC_TOLERANCE) + { + // Yes. Proceed to split. + uint8_t* pMem = (uint8_t*)&pHeader[1] + sz; + + // This will be the location of the new memory header. + MemAreaHeader* pNewHdr = (MemAreaHeader*)pMem; + + // Map it in memory. + MemMgrUseMemoryRegion(pNewHdr, sizeof (MemAreaHeader)); + + // Initialize its magic bits. + pNewHdr->m_magicNo1 = MAGIC_NUMBER_1_FREE; + pNewHdr->m_magicNo2 = MAGIC_NUMBER_2_FREE; + pNewHdr->m_size = pHeader->m_size - sizeof(MemAreaHeader) - sz; + pHeader->m_size = sz; + // Link it up with the nodes in between + pNewHdr->m_pNext = pHeader->m_pNext; + if (pHeader->m_pNext) pHeader->m_pNext->m_pPrev = pNewHdr; + pNewHdr->m_pPrev = pHeader; + pHeader->m_pNext = pNewHdr; + + if (pHeader == gLastHeader) + { + gLastHeader = pNewHdr; + g_bAddedToLastHeaderHint = true; + } + else + { + g_bAddedToLastHeaderHint = false; + } + } + else + { + // Don't split it. + + if (pHeader == gLastHeader) + { + gLastHeader = NULL; + g_bAddedToLastHeaderHint = false; + } + } + + // Update this header's magic numbers, to mark this block used. + pHeader->m_magicNo1 = MAGIC_NUMBER_1_USED; + pHeader->m_magicNo2 = MAGIC_NUMBER_2_USED; + + MemMgrUseMemoryRegion(pHeader, sz + sizeof (MemAreaHeader)); + + // return the memory right after the header. + return &pHeader[1]; + } + + // Nope! Simply skip, as done below. + } + + pLastHeader = pHeader; + pHeader = pHeader->m_pNext; + } + + // try to expand. If doesn't work, we have run into an out of memory situation. + uint8_t* pMem = NULL; + + if (pLastHeader) + { + pMem = (uint8_t*)&pLastHeader[1] + pLastHeader->m_size; + } + else + { + LogMsg("ERROR: No pLastHeader? (line %d)", __LINE__); + MemMgrAbort(); + } + + if (pMem + sz >= gMemory + gMemorySize) + { + // yikes! + LogMsg("Out of memory area! (trying to allocate size %d)", sz); + return NULL; + } + + assert(pLastHeader->m_pNext == NULL); + + // This will be the location of the new memory header. + MemAreaHeader* pNewHdr = (MemAreaHeader*)pMem; + + // Map the relevant memory area + MemMgrUseMemoryRegion(pNewHdr, sizeof (MemAreaHeader)); + + // update the bits + pNewHdr->m_magicNo1 = MAGIC_NUMBER_1_USED; + pNewHdr->m_magicNo2 = MAGIC_NUMBER_2_USED; + pNewHdr->m_pPrev = pLastHeader; + pNewHdr->m_pNext = NULL; + pLastHeader->m_pNext = pNewHdr; + pNewHdr->m_size = sz; + + gLastHeader = pNewHdr; + + g_bAddedToLastHeaderHint = true; + + MemMgrUseMemoryRegion(pNewHdr, sz + sizeof (MemAreaHeader)); + + return &pNewHdr[1]; +} + +void MemMgrFreeMemory(void *pMem) +{ + if (pMem == NULL) + return; + + // check the padding first + if (((uintptr_t)pMem & (SIZE_AND_LOCATION_PADDING - 1)) != 0) + { + LogMsg("Error: Address passed in is NOT padded to %d!", SIZE_AND_LOCATION_PADDING); + abort(); + } + + // get the header right before the memory with some cool syntax tricks + MemAreaHeader* pHeader = & (-1)[(MemAreaHeader*)pMem]; + + if (gLastHeader == pHeader) + { + gLastHeader = NULL; + g_bAddedToLastHeaderHint = false; + } + + // Ensure the sanity of this header + MemMgrPerformSanityChecks(pHeader); + + // already free? + if (pHeader->m_magicNo1 == MAGIC_NUMBER_1_FREE && pHeader->m_magicNo2 == MAGIC_NUMBER_2_FREE) + { + LogMsg("ERROR: double free attempt at %p", pMem); + MemMgrAbort(); + } + + // mark it as free + pHeader->m_magicNo1 = MAGIC_NUMBER_1_FREE; + pHeader->m_magicNo2 = MAGIC_NUMBER_2_FREE; + + MemMgrFreeMemoryRegion(pHeader, pHeader->m_size + sizeof(MemAreaHeader)); + + // if it's sufficiently large, we may want to stop allocating right at the end of our heap + if (pHeader->m_size >= C_MEM_FREE_LARGE_ENOUGH) + { + g_bAddedToLastHeaderHint = false; + } + + // try to combine with other free slots + MemAreaHeader* pNext = pHeader->m_pNext; + + // Does it exist, and is it free? + if (pNext && IS_FREE(pNext)) + { + // yeah. Merge this and the next together. + pHeader->m_size += pNext->m_size + sizeof (MemAreaHeader); + pHeader->m_pNext = pNext->m_pNext; + if (pNext->m_pNext) pNext->m_pNext->m_pPrev = pHeader; + + // well, pNext is no longer valid, get rid of its magic numbers. + pNext->m_magicNo1 = 0; + pNext->m_magicNo2 = 0; + + // mark it as unused + MemMgrFreeMemoryRegion(pNext, 1); + } + + MemAreaHeader* pPrev = pHeader->m_pPrev; + + // Does it exist? Is it free? + if (pPrev && IS_FREE(pPrev)) + { + // yeah. Merge this and the previous together. + pPrev->m_size += pHeader->m_size + sizeof (MemAreaHeader); + pPrev->m_pNext = pHeader->m_pNext; + if (pHeader->m_pNext) pPrev->m_pNext->m_pPrev = pPrev; + + // well our pHeader is no longer valid, get rid of its magic numbers. + pHeader->m_magicNo1 = 0; + pHeader->m_magicNo2 = 0; + + // mark it as unused + MemMgrFreeMemoryRegion(pHeader, 1); + } +} + +/* +void* MemMgrReAllocateMemory(void* pMem, size_t size) +{ + if (pMem == NULL) + pMem = NULL; + + if (!pMem) + return MemMgrAllocateMemory(size); + + // get the header right before the memory with some cool syntax tricks + MemAreaHeader* pHeader = & (-1)[(MemAreaHeader*)pMem]; + + // Ensure the sanity of this header + MemMgrPerformSanityChecks(pHeader); + + void* pNewMem = MemMgrAllocateMemory(size); + if (!pNewMem) + return NULL; + + size_t minSize = pHeader->m_size; + if (minSize > size) + minSize = size; + + memcpy(pNewMem, pMem, minSize); + + MemMgrFreeMemory(pMem); + + return pNewMem; +} +*/ + +void* MemMgrReAllocateMemory(void* pMem, size_t size) +{ + // get the header right before the memory with some cool syntax tricks + MemAreaHeader* pHeader = & (-1)[(MemAreaHeader*)pMem]; + + // Ensure the sanity of this header + MemMgrPerformSanityChecks(pHeader); + + if (gLastHeader == pHeader) + { + gLastHeader = NULL; + g_bAddedToLastHeaderHint = false; + } + + // Actually, is the size the same? + if (size == pHeader->m_size) + { + return pMem; + } + + // Are we trying to shrink this memory region? This case is trivial. + if (size < pHeader->m_size) + { + // Temporarily add a separate reference to the memory of this header. + // This will ensure that no memory gets removed when we remove the + // other references later. + MemMgrUseMemoryRegion(pHeader, size + sizeof(MemAreaHeader)); + + // Get rid of the references from the old header. + MemMgrFreeMemoryRegion(pHeader, pHeader->m_size + sizeof(MemAreaHeader)); + + // Update the size of this header. + pHeader->m_size = size; + + return pMem; + } + + // TODO: fix this code + /* + + // How much space do we have between this and the next header? + MemAreaHeader* pNext = pHeader->m_pNext; + + if ((uintptr_t)(pNext) >= (uintptr_t)pHeader + sizeof(MemAreaHeader) + size) + { + // Yes. Expand this area using the same method as above for shrinking. + MemMgrUseMemoryRegion(pHeader, size + sizeof(MemAreaHeader)); + + // Get rid of the references from the old header. + MemMgrFreeMemoryRegion(pHeader, pHeader->m_size + sizeof(MemAreaHeader)); + + // Update the size of this header. + pHeader->m_size = size; + + return pMem; + } + + */ + + // We can't! Means we need to relocate. + void * pNewMem = MemMgrAllocateMemory(size); + if (!pNewMem) return NULL; + + memcpy(pNewMem, pMem, pHeader->m_size); + + MemMgrFreeMemory(pMem); + + return pNewMem; +} + +void MemMgrDebugDump() +{ + MemAreaHeader* pHeader = MemMgrGetInitialHeader(); + + while (pHeader) + { + // Perform a sanity check first, before doing *anything*. Has its reasons. + MemMgrPerformSanityChecks(pHeader); + + SLogMsg("Header: %p. Next: %p, Prev: %p. Size: %u.", pHeader, pHeader->m_pNext, pHeader->m_pPrev, pHeader->m_size); + + pHeader = pHeader->m_pNext; + } + + SLogMsg("Memory page reference: "); + + for (int i = 0; i < 50; i++) + SLogMsgNoCr("%x", gMemoryPageReference[i]); + + SLogMsgNoCr("\n"); +} + +void MemMgrCleanup() +{ + // I think we can just do this. Pages whose page mapping isn't set are ignored. + MemMgrRequestMemUnMap((uintptr_t)gMemory, gMemorySize); +} + +// On out of memory +void MemOnOOM(int errCode, bool bUnmappingMemory) +{ + LogMsg("ERROR: ran out of memory (?). Was%s unmapping, error code: %d. Will now quit.", bUnmappingMemory ? "" : "n't", errCode); + + abort(); +} + +void _I_FreeEverything() +{ + MemMgrCleanup(); +} + +void* realloc (void * ptr, size_t size) +{ + if (!ptr) return malloc(size); + + return MemMgrReAllocateMemory(ptr, size); +} + +void *malloc (size_t sz) +{ + void* ptr = MemMgrAllocateMemory(sz); + + // if we have obtained some memory, scrub it + if (ptr) memset(ptr, 0x69, sz); + + return ptr; +} + +void *calloc (size_t nmemb, size_t size) +{ + void *ptr = MemMgrAllocateMemory(nmemb * size); + + if (ptr == NULL) return ptr; + + memset(ptr, 0, nmemb * size); + return ptr; +} + +void free (void* pMem) +{ + if (!pMem) return; + + return MemMgrFreeMemory(pMem); +} + +// Allocating kernel regions, if needed. Will cause a memory leak if not disposed of properly, so use carefully!!! +void* MmKernelAllocate(size_t sz) +{ + return _I_AllocateDebug(sz, __FILE__, __LINE__); +} + +void MmKernelFree(void *pData) +{ + _I_Free(pData); +} + +void * MmKernelReAllocate(void* ptr, size_t sz) +{ + return _I_ReAllocateDebug(ptr, sz, __FILE__, __LINE__); +} diff --git a/crt2/src/a_printf.c b/crt2/src/a_printf.c new file mode 100644 index 00000000..2272dda1 --- /dev/null +++ b/crt2/src/a_printf.c @@ -0,0 +1,566 @@ +// *************************************************************** +// a_printf.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +int fwrite(const void* ptr, size_t sz, size_t nmemb, FILE* stream); +extern FILE* stdout; + +#if SIZE_MAX == 0xFFFFFFFFFFFFFFFFull +#define IS_64_BIT 1 +#else +#define IS_64_BIT 0 +#endif + +// printf implementation + +void uns_to_str(uint64_t num, char* str, int paddingInfo, char paddingChar) +{ + // print the actual digits themselves + int i = 0; + while (num || i == 0) + { + str[i++] = '0' + (num % 10); + str[i] = '\0'; + num /= 10; + } + + // append padding too + for (; i < paddingInfo; ) + { + str[i++] = paddingChar; + str[i] = '\0'; + } + + // reverse the string + int start = 0, end = i - 1; + while (start < end) + { + char + temp = str[start]; + str[start] = str[end]; + str[end] = temp; + start++; + end--; + } +} +void int_to_str(int64_t num, char* str, int paddingInfo, char paddingChar) +{ + if (num < 0) + { + str[0] = '-'; + uns_to_str((uint64_t)(-num), str + 1, paddingInfo, paddingChar); + } + else + uns_to_str((uint64_t) num, str, paddingInfo, paddingChar); +} + +// features: +// %s, %S = prints a string +// %c, %C = prints a char +// %d, %i, %D, %I = prints an int32 +// %u, %U = prints a uint32 +// %l = prints a uint64 +// %L = prints an int64 +// %x, %X = prints a uint32 in hex in lowercase or uppercase respectively +// %q, %Q = prints a uint64 in hex in lowercase or uppercase respectively +// %b, %B = prints a uint16 in hex in lowercase or uppercase respectively +// %w, %W = prints a uint8 in hex in lowercase or uppercase respectively +// %p, %P = prints a pointer address (fully platform dependent) + +int vsnprintf(char* buf, size_t sz, const char* fmt, va_list args) +{ + int paddingInfo = -1; + char paddingChar = ' '; + size_t currentIndex = 0; + while (*fmt) + { + char m = *fmt; + if (!m) goto finished; + fmt++; + + if (m == '%') + { + m = *(fmt++); + + // if hit end, return + if (!m) goto finished; + + // handle %0 or %. + if (m == '0' || m == '.') + { + // this by default handles %0 too, though it does nothing + paddingInfo = 0; + m = *(fmt++); + + // if hit end, return + if (!m) goto finished; + + // handle %0D cases (D = digit) + if (m >= '0' && m <= '9') + { + paddingInfo = m - '0'; + paddingChar = '0'; + m = *(fmt++); + } + } + else if (m >= '1' && m <= '9') + { + paddingInfo = m - '0'; + paddingChar = ' '; + m = *(fmt++); + + // if hit end, return + if (!m) goto finished; + } + + switch (m) + { + // Format a string + case 's': case 'S': + { + const char* pString = va_arg(args, const char*); + + //allow user to print null + if (pString == NULL) + pString = "(null)"; + + while (*pString) + { + if (currentIndex >= sz - 1) + goto finished; + + // place this character here + buf[currentIndex++] = *pString; + + pString++; + } + + break; + } + // Escape a percentage symbol + case '%': + { + if (currentIndex >= sz - 1) + goto finished; + + buf[currentIndex++] = '%'; + break; + } + // Format a char + case 'c': case 'C': + { + // using va_arg(args, char) has undefined behavior, because + // char arguments will be promoted to int. + char character = (char)va_arg(args, int); + + if (currentIndex >= sz - 1) + goto finished; + + buf[currentIndex++] = character; + break; + } + // Format an int + case 'd': case 'i': case 'D': case 'I': + { + int num = va_arg(args, int); + char buffer[20]; + + int_to_str(num, buffer, paddingInfo, paddingChar); + + const char* pString = buffer; + while (*pString) + { + if (currentIndex >= sz - 1) + goto finished; + + // place this character here + buf[currentIndex++] = *pString; + + pString++; + } + + break; + } + // Format an unsigned int + #if !IS_64_BIT + case 'z': + { + m = *(fmt++); + if (m == 0) goto finished; + //fallthrough intended + } + #endif + case 'u': case 'U': + { + uint32_t num = va_arg(args, uint32_t); + char buffer[20]; + + uns_to_str(num, buffer, paddingInfo, paddingChar); + + const char* pString = buffer; + while (*pString) + { + if (currentIndex >= sz - 1) + goto finished; + + // place this character here + buf[currentIndex++] = *pString; + + pString++; + } + + break; + } + // Format a longer integer. + #if IS_64_BIT + case 'z': + #endif + case 'l': + { + bool longlong = false; + #if IS_64_BIT + if (m == 'z') + { + longlong = true; + m = 'u'; + goto __parse_the_thing; + } + #endif + m = *(fmt++); + if (m == 'l') + { + longlong = true; + m = *(fmt++); + } + if (m == 0) goto finished; + + #if IS_64_BIT + __parse_the_thing: + #endif + + const char* pString = NULL; + char buffer[30]; + buffer[0] = 0; + pString = buffer; + + if (m == 'u') + { + unsigned long long num = longlong ? va_arg(args, unsigned long long) : va_arg(args, unsigned long); + uns_to_str(num, buffer, paddingInfo, paddingChar); + } + if (m == 'd') + { + long long num = longlong ? va_arg(args, long long) : va_arg(args, long); + int_to_str(num, buffer, paddingInfo, paddingChar); + } + + if (!pString) break; + + while (*pString) + { + if (currentIndex >= sz - 1) + goto finished; + + // place this character here + buf[currentIndex++] = *pString; + + pString++; + } + break; + } + // Format a uint8_t as lowercase/uppercase hexadecimal + case 'b': + case 'B': + { + const char* charset = "0123456789abcdef"; + if (m == 'B') + charset = "0123456789ABCDEF"; + + // using va_arg(args, uint8_t) has undefined behavior, because + // uint8_t arguments will be promoted to int. + uint8_t p = (uint8_t) va_arg(args, uint32_t); + + if (currentIndex >= sz - 1) goto finished; + buf[currentIndex++] = charset[(p & 0xF0) >> 4]; + if (currentIndex >= sz - 1) goto finished; + buf[currentIndex++] = charset[p & 0x0F]; + + break; + } + // Format a uint16_t as lowercase/uppercase hexadecimal + case 'w': + case 'W': + { + const char* charset = "0123456789abcdef"; + if (m == 'W') + charset = "0123456789ABCDEF"; + + // using va_arg(args, uint16_t) has undefined behavior, because + // uint16_t arguments will be promoted to int. + uint16_t p = (uint16_t) va_arg(args, uint32_t); + + for (uint32_t mask = 0xF000, bitnum = 12; mask; mask >>= 4, bitnum -= 4) + { + if (currentIndex >= sz - 1) + goto finished; + + // place this character here + buf[currentIndex++] = charset[(p & mask) >> bitnum]; + } + + break; + } + // Format a uint32_t as lowercase/uppercase hexadecimal + case 'x': + case 'X': +#if !IS_64_BIT + case 'p': case 'P': +#endif + { + const char* charset = "0123456789abcdef"; + if (m == 'X' || m == 'P') + charset = "0123456789ABCDEF"; + + uint32_t p = va_arg(args, uint32_t); + + for (uint32_t mask = 0xF0000000, bitnum = 28; mask; mask >>= 4, bitnum -= 4) + { + if (currentIndex >= sz - 1) + goto finished; + + // place this character here + buf[currentIndex++] = charset[(p & mask) >> bitnum]; + } + + break; + } + // Format a uint64_t as lowercase/uppercase hexadecimal + case 'q': + case 'Q': +#if IS_64_BIT + case 'p': case 'P': +#endif + { + const char* charset = "0123456789abcdef"; + if (m == 'Q' || m == 'P') + charset = "0123456789ABCDEF"; + + uint64_t p = va_arg(args, uint64_t); + + for (uint64_t mask = 0xF000000000000000ULL, bitnum = 60; mask; mask >>= 4, bitnum -= 4) + { + if (currentIndex >= sz - 1) + goto finished; + + // place this character here + buf[currentIndex++] = charset[(p & mask) >> bitnum]; + } + + break; + } + } + } + else + { + if (currentIndex >= sz - 1) + goto finished; + buf[currentIndex++] = m; + } + } +finished: + buf[currentIndex] = '\0'; + return (int)currentIndex; +} + +int vsprintf(char* buf, const char* fmt, va_list args) +{ + return vsnprintf(buf, SIZE_MAX, fmt, args); +} + +int snprintf(char* buf, size_t sz, const char* fmt, ...) +{ + va_list lst; + va_start(lst, fmt); + + int val = vsnprintf(buf, sz, fmt, lst); + + va_end(lst); + + return val; +} + +int sprintf(char* buf, const char* fmt, ...) +{ + va_list lst; + va_start(lst, fmt); + + int val = vsprintf(buf, fmt, lst); + + va_end(lst); + + return val; +} + +// This is a hack. I may remove it. + +void _I_WritePort(short port, char c) +{ + __asm__("outb %1, %0\n\t"::"d"(port),"a"(c)); +} + +void _I_SPutString(const char* s) +{ + while (*s) + { + _I_WritePort(0xE9, *s); + s++; + } +} + +void LogMsg(const char* fmt, ...) +{ + char cr[8192]; + va_list list; + va_start(list, fmt); + vsnprintf(cr, sizeof(cr) - 2, fmt, list); + + snprintf(cr + strlen(cr), 2, "\n"); + _I_PutString(cr); + + va_end(list); +} + +void SLogMsg(const char* fmt, ...) +{ + char cr[8192]; + va_list list; + va_start(list, fmt); + vsnprintf(cr, sizeof(cr) - 2, fmt, list); + + snprintf(cr + strlen(cr), 2, "\n"); + _I_SPutString(cr); + + va_end(list); +} + +void SLogMsgNoCr(const char* fmt, ...) +{ + char cr[8192]; + va_list list; + va_start(list, fmt); + vsnprintf(cr, sizeof(cr) - 1, fmt, list); + _I_SPutString(cr); + + va_end(list); +} + +void LogMsgNoCr(const char* fmt, ...) +{ + char cr[8192]; + va_list list; + va_start(list, fmt); + vsnprintf(cr, sizeof(cr), fmt, list); + + _I_PutString(cr); + + va_end(list); +} + +int printf(const char* fmt, ...) +{ + char cr[8192]; + va_list list; + va_start(list, fmt); + vsnprintf(cr, sizeof(cr), fmt, list); + + _I_PutString(cr); + + va_end(list); + return strlen(cr); +} + +int vfprintf(FILE* file, const char* fmt, va_list list) +{ + char cr[8192]; + vsnprintf(cr, sizeof(cr), fmt, list); + + int slen = strlen(cr); + int result = fwrite(cr, 1, slen, file); + + return result; +} + +int fprintf(FILE* file, const char* fmt, ...) +{ + va_list list; + va_start(list, fmt); + + int res = vfprintf(file, fmt, list); + + va_end(list); + + return res; +} + +int fputs(const char* s, FILE * stream) +{ + size_t sz = strlen(s); + return fwrite(s, 1, sz, stream); +} + +int fputc(int c, FILE * stream) +{ + char chr = (char)c; + return fwrite(&chr, 1, 1, stream); +} + +int puts(const char * s) +{ + _I_PutString(s); + _I_PutString("\n"); + return strlen(s) + 1; +} + +int putc(int c, FILE* stream) +{ + return fputc(c, stream); +} + +int putchar(int c) +{ + return fputc(c, stdout); +} + +void vprintf(const char* fmt, va_list list) +{ + vfprintf(stdout, fmt, list); +} + +const char* strerror(int errnum); +int GetErrorNumber(); + +void perror(const char* fmt, ...) +{ + char cr[8192]; + va_list list; + va_start(list, fmt); + vsnprintf(cr, sizeof(cr), fmt, list); + + _I_PutString(cr); + + va_end(list); + + // print the error now: + _I_PutString(": "); + _I_PutString(strerror(GetErrorNumber())); + _I_PutString("\n"); +} diff --git a/crt2/src/a_sort.c b/crt2/src/a_sort.c new file mode 100644 index 00000000..84e8d00b --- /dev/null +++ b/crt2/src/a_sort.c @@ -0,0 +1,65 @@ +// *************************************************************** +// a_sort.c - Creation date: 29/12/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** +#include "crtlib.h" + +// TODO: Implement a more efficient sorting algorithm. We will just use bubble sorting +// for now, since the spec doesn't say what algorithm we should be using. + +static __attribute__((always_inline)) +void swap_char(char * c, char * d) +{ + char tmp = *c; + *c = *d; + *d = tmp; +} + +void qsort(void *pBase, size_t nCount, size_t nElementSize, ComparisonFunc pCompare) +{ + for (size_t i = 0; i < nCount; i++) + { + void *p1 = (void *)((uintptr_t)pBase + i * nElementSize); + + for (size_t j = i + 1; j < nCount; j++) + { + void *p2 = (void *)((uintptr_t)pBase + j * nElementSize); + if (pCompare(p1, p2) <= 0) + continue; + + // swap p1 and p2 + char *p1_bytes = (char *)p1; + char *p2_bytes = (char *)p2; + + for (size_t k = 0; k < nElementSize; k++) + swap_char(&p1_bytes[k], &p2_bytes[k]); + } + } +} + +void qsort_r(void *pBase, size_t nCount, size_t nElementSize, ComparisonReentrantFunc pCompareReentrant, void* pArgument) +{ + for (size_t i = 0; i < nCount; i++) + { + void *p1 = (void *)((uintptr_t)pBase + i * nElementSize); + + for (size_t j = i + 1; j < nCount; j++) + { + void *p2 = (void *)((uintptr_t)pBase + j * nElementSize); + if (pCompareReentrant(p1, p2, pArgument) <= 0) + continue; + + // swap p1 and p2 + char *p1_bytes = (char *)p1; + char *p2_bytes = (char *)p2; + + for (size_t k = 0; k < nElementSize; k++) + swap_char(&p1_bytes[k], &p2_bytes[k]); + } + } +} diff --git a/crt2/src/a_string.c b/crt2/src/a_string.c new file mode 100644 index 00000000..18055e24 --- /dev/null +++ b/crt2/src/a_string.c @@ -0,0 +1,949 @@ +// *************************************************************** +// a_string.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" +#include + +// Character operations + +int isalnum(int c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); +} + +int isalpha(int c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +int isascii(int c) +{ + return (c >= 0 && c < 0x80); +} + +int isblank(int c) +{ + return (c == ' ' || c == '\n' || c == '\0'); +} + +int iscntrl(int c) +{ + return (c >= 0 && c <= 0x1F); +} + +int isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +int isgraph(int c) +{ + return (c >= '!' && c <= 0x7E); +} + +int islower(int c) +{ + return (c >= 'a' && c <= 'z'); +} + +int isprint(int c) +{ + return (c >= ' ' && c <= 0x7E); +} + +int isspace(int c) +{ + return (c == ' ' || c == '\n'); +} + +int isupper(int c) +{ + return (c >= 'A' && c <= 'Z'); +} + +int isxdigit(int c) +{ + return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9'); +} + +int tolower (int c) +{ + if (isupper(c)) return c + ('a' - 'A'); else return c; +} + +int toupper (int c) +{ + if (islower(c)) return c - ('a' - 'A'); else return c; +} + +// Memory operations. + +int memcmp(const void* ap, const void* bp, size_t size) +{ + const char* a = (const char*) ap; + const char* b = (const char*) bp; + for (size_t i = 0; i < size; i++) + { + if (a[i] != b[i]) + return a[i] - b[i]; + } + return 0; +} + +void* memmove(void* dstptr, const void* srcptr, size_t size) +{ + uint8_t* dst = dstptr; + const uint8_t* src = srcptr; + + // test for overlap + if (src + size > dst || dst + size > src) + { + // overlap found. depending on the direction, copy a different way + if (dst < src) + { + while (size--) + *dst++ = *src++; + } + //move backwards + else + { + dst += size; + src += size; + + while (size--) + *(--dst) = *(--src); + } + } + else + { + while (size--) + *dst++ = *src++; + } + + return dstptr; +} + +void* memcpy(void* dstptr, const void* srcptr, size_t size) +{ + // simply copy: + uint8_t* dst = dstptr; + const uint8_t* src = srcptr; + + while (size--) + *dst++ = *src++; + + return dstptr; +} + +void* memset(void* bufptr, int val, size_t size) +{ + uint8_t* buf = bufptr; + while (size--) + *buf++ = val; + + return bufptr; +} + +// String operations. + +size_t strgetlento(const char* str, char chr) +{ + size_t len = 0; + while (str[len] != chr) + { + len++; + } + return len; +} + +int atoi(const char* str) +{ + int f = 0; + int s = 1; + int i = 0; + if (str[0] == '-') + { + i++; + s = -1; + } + for (; str[i] != '\0'; i++) + f = f * 10 + str[i] - '0'; + + return s * f; +} + +long atol(const char* str) +{ + long f = 0; + long s = 1; + long i = 0; + if (str[0] == '-') + { + i++; + s = -1; + } + for (; str[i] != '\0'; i++) + f = f * 10 + str[i] - '0'; + + return s * f; +} + +long long atoll(const char* str) +{ + long long f = 0; + long long s = 1; + long long i = 0; + if (str[0] == '-') + { + i++; + s = -1; + } + for (; str[i] != '\0'; i++) + f = f * 10 + str[i] - '0'; + + return s * f; +} + +size_t strlen(const char* str) +{ + size_t len = 0; + while (*str++) + len++; + + return len; +} + +char* strcpy(char* ds, const char* ss) +{ + char* dso = ds; + + while (*ss) + { + *ds++ = *ss++; + } + + return dso; +} + +void strtolower(char* as) +{ + while(*as != 0) + { + if(*as >= 'A' && *as <= 'Z') + *as += ('a' - 'A'); + as++; + } +} + +void strtoupper(char* as) +{ + while(*as != 0) + { + if(*as >= 'a' && *as <= 'z') + *as -= ('a' - 'A'); + as++; + } +} + +void memtolower(char* as, int w) +{ + int a = 0; + while(a <= w) + { + if(*as >= 'A' && *as <= 'Z') + *as += ('a' - 'A'); + as++; + a++; + } +} + +void memtoupper(char* as, int w) +{ + int a = 0; + while(a <= w) + { + if(*as >= 'a' && *as <= 'z') + *as -= ('a' - 'A'); + as++; + a++; + } +} + +int strcmp(const char* s1, const char* s2) +{ + while (true) + { + // If we've reached the end in both cases, they're equal + if (!*s1 && !*s2) + return 0; + + // If either one of these pointers points to a null character, + // it's fine. + if (*s1 != *s2) + return *s1 - *s2; + + s1++, s2++; + } +} + +char* strcat(char* dest, const char* after) +{ + char* destold = dest; + + // go to the end + while (*dest++); + + // strcpy the src string over + strcpy(dest, after); + + return destold; +} + +char* strchr (const char* str, int c); + +char* Tokenize (TokenState* pState, char* pString, char* separator) +{ + int len, i; + + if(!pState->m_bInitted) + { + pState->m_bInitted = 1; + pState->m_pContinuation = NULL; + pState->m_pReturnValue = NULL; + } + else if (!pState->m_pContinuation) + { + return NULL; + } + + if(!pString) + { + pString = pState->m_pContinuation; + } + + if (!pString) + { + return NULL; + } + + len = strlen (pString); + + for (i = 0; i < len; i++) + { + if (strchr(separator, pString[i])) + { + pState->m_pContinuation = &pString[i+1]; + pString[i] = 0; + pState->m_pReturnValue = pString; + return pString; + } + } + + // not found, hit null term: + pState->m_pContinuation = NULL; + pState->m_pReturnValue = pString; + return pString; +} + +void *malloc (size_t size); + +char *strdup (const char *pText) +{ + size_t len = strlen (pText) + 1; + char *p = malloc (len); + if (p) + memcpy (p, pText, len); + return p; +} + +char * strncpy(char *dst, const char *src, size_t n) +{ + size_t i; + for (i = 0; i < n && src[i] != '\0'; i++) + dst[i] = src[i]; + for (; i < n; i++) + dst[i] = '\0'; + return dst; +} + +size_t strlcpy(char *dst, const char *src, size_t n) +{ + n--; + size_t i; + size_t srclen = 0; + for (i = 0; i < n && src[i] != '\0'; i++) + { + dst[i] = src[i]; + srclen++; + } + dst[i] = '\0'; + + // traverse the rest of src to get its length: + while (src[i++]) + srclen++; + + return srclen; +} + +char* ltoa(long ival, char* buffer, int radix) +{ + assert(radix > 1 && radix < 37); + const char* lut = "0123456789abcdefghijklmnopqrstuvwxyz"; + + char temp[50]; + int i = 0; + + unsigned long value = (unsigned long)ival; + + if (ival < 0) + { + value = -ival; + *buffer++ = '-'; + } + + do + { + temp[i++] = lut[value % radix]; + value /= radix; + } + while (value); + + // store it as reversed + for (int j = 0; j < i; j++) + buffer[j] = temp[i - j - 1]; + + return buffer; +} + +char* itoa(int value, char* buffer, int radix) +{ + return ltoa(value, buffer, radix); +} + +static char* strchr_i(const char* s, int c, bool bReturnNulPos) +{ + // promotion to 'char' intended + char* sc = (char*) s; + + while (*sc) + { + if (*sc == c) return sc; + + sc++; + } + + if (c == 0) + { + return sc; + } + + // assert(*sc == 0); + + return bReturnNulPos ? sc : NULL; +} + +char* strchr(const char* s, int c) +{ + return strchr_i(s, c, false); +} + +char* strchrnul(const char* s, int c) +{ + return strchr_i(s, c, true); +} + +char* strrchr(const char* s, int c) +{ + // promotion to 'char' intended + char* sc = (char*) s; + while (*sc) sc++; + + while (sc != s) + { + sc--; + if (*sc == c) return sc; + } + + return NULL; +} + +int atox(const char* str) +{ + int f = 0; + int s = 1; + int i = 0; + if (str[0] == '-') + { + i++; + s = -1; + } + for (; str[i] != '\0'; i++) + { + f = f * 16; + if (str[i] >= 'a' && str[i] <= 'f') + f += str[i] - 'a' + 0xa; + else if (str[i] >= 'A' && str[i] <= 'F') + f += str[i] - 'A' + 0xA; + else + f += str[i] - '0'; + } + + return s * f; +} + +size_t strnlen(const char* ptext, size_t n) +{ + size_t k = 0; + while (*ptext) + { + k++; + if (k == n) return n; + ptext++; + } + return k; +} + +int strncmp(const char *s1, const char *s2, register size_t n) +{ + unsigned char u1, u2; + while (n-- > 0) + { + u1 = (unsigned char) *s1++; + u2 = (unsigned char) *s2++; + if (u1 != u2) + return u1 - u2; + if (u1 == '\0') + return 0; + } + return 0; +} + +char* strstr(const char *haystack, const char *needle) +{ + const size_t len_nd = strlen(needle); + const size_t len_hs = strlen(haystack); + + if (len_nd > len_hs) + return NULL; // needle is too big to be in the haystack + + if (len_nd == len_hs) + { + if (strcmp(haystack, needle) == 0) + return (char*)haystack; + return NULL; + } + + const size_t len = len_hs - len_nd; + + for (size_t i = 0; i < len; i++) + { + if (strncmp(haystack + i, needle, len_nd) == 0) + return (char*)haystack + i; + } + + return NULL; +} + +size_t strspn(const char* s, const char* accept) +{ + const uint8_t* str = (const uint8_t*)s; + const uint8_t* acc = (const uint8_t*)accept; + + bool lut[256]; // could be a bitset, but nah, not right now + memset (&lut, 0, sizeof lut); + while (*acc) + { + // cast to unsigned because negative indices aren't a thing + lut[*acc++] = 1; + } + + size_t matching = 0; + + while (*str) + { + if (!lut[*str]) + return matching; + matching++; + str++; + } + + return matching; +} + +size_t strcspn(const char* s, const char* reject) +{ + const uint8_t* str = (const uint8_t*)s; + const uint8_t* rej = (const uint8_t*)reject; + + bool lut[256]; // could be a bitset, but nah, not right now + memset (&lut, 0, sizeof lut); + while (*rej) + { + // cast to unsigned because negative indices aren't a thing + lut[*rej++] = 1; + } + + size_t matching = 0; + + while (*str) + { + if (lut[*str]) + return matching; + matching++; + str++; + } + + return matching; +} + +void* memchr(const void* s, int c, size_t n) +{ + const uint8_t* ptr = s; + uint8_t match = c; + + while (n--) + { + if (*ptr == match) + return (void*)ptr; + + ptr++; + } + + return NULL; +} + +void* memrchr(const void* s, int c, size_t n) +{ + const uint8_t* ptr = s; + uint8_t match = c; + + ptr += n; + + while (n--) + { + ptr--; + + if (*ptr == match) + return (void*)ptr; + } + + return NULL; +} + +void* rawmemchr(const void* s, int c) +{ + const uint8_t* ptr = s; + uint8_t match = c; + + while (true) + { + if (*ptr == match) + return (void*)ptr; + + ptr++; + } +} + +double atof(const char *arr) +{ + double value = 0; + bool decimal = 0; + double scale = 1; + int negative = 0; + + // parse the negative sign + if (*arr == '-') + { + arr++; + negative = 1; + } + + while (*arr) + { + // if we're parsing the decimal part + if (decimal) + { + scale /= 10; + value += (*arr - '0') * scale; + } + else + { + if (*arr == '.') + decimal = 1; + else + value = value * 10.0 + (*arr - '0'); + } + arr++; + } + + if (negative) value = -value; + + return value; +} + +#include +#include +#include + +// String to Unsigned X. +unsigned long long strtoux(const char* str, char ** endptr, int base, unsigned long long max) +{ + errno = 0; + unsigned long long val = 0; + + // skip white space + while (*str && isspace(*str)) str++; + if (*str == '\0') + { + //well, we haven't really found any numbers + if (endptr) + *endptr = (char*)str; + errno = EINVAL; + return 0; + } + + // *str isn't zero, so surely *(str+1) can be accessed. Check it + if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) + { + if (base == 0 || base == 16) + { + base = 16; + str += 2; + } + else + { + // well, base wasn't either 16 or zero and we've still got the 0x prefix. + // Set endptr to point to 'x' and return + if (endptr) + *endptr = (char*)&str[1]; + return 0; + } + } + // if we're starting with zero, we're handling octal + else if (*str == '0') + { + if (base == 0 || base == 8) + base = 8; + str++; + } + + // if base is STILL zero, then we're dealing with decimal. + if (base == 0) base = 10; + + // keep reading digits + while (*str) + { + int digit = 0; + if (*str >= '0' && *str <= '9') + digit = *str - '0'; + else if (*str >= 'A' && *str <= 'Z') + digit = *str - 'A' + 10; + else if (*str >= 'a' && *str <= 'z') + digit = *str - 'a' + 10; + else + // we've reached the end. + break; + + // check in what situation we are about to overflow. + + // max without the last digit. + unsigned long long maxwld = max / base; + // if the value exceeds the max without the last digit already, this means that any digit we add will make it fail. + if (val > maxwld) + { + val = max; + errno = ERANGE; + if (endptr) *endptr = (char*)str; + return val; + } + // if it's equal + if (val == maxwld) + { + int digthresh = max % base; + + // if we're trying to tack on a digit bigger than the max's last digit, then we're going to overflow, so don't + if (digit > digthresh) + { + val = max; + errno = ERANGE; + if (endptr) *endptr = (char*)str; + return val; + } + } + + // if it's none of these, whatever digit we add will be valid. + val = val * base + digit; + + str++; + } + + if (endptr) + *endptr = (char*)str; + + return val; +} + +// String to Signed X. +long long strtox(const char* str, char ** endptr, int base, long long max) +{ + errno = 0; + + long long val = 0; long long sign = 1; + long long min = -max - 1; + + // skip white space + while (*str && isspace(*str)) str++; + if (*str == '\0') + { + //well, we haven't really found any numbers + if (endptr) + *endptr = (char*)str; + errno = EINVAL; + return 0; + } + + // if we have a sign, treat it + if (*str == '+' || *str == '-') + { + sign = (*str == '-') ? (-1) : (1); + str++; + } + + // *str isn't zero, so surely *(str+1) can be accessed. Check it + if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) + { + if (base == 0 || base == 16) + { + base = 16; + str += 2; + } + else + { + // well, base wasn't either 16 or zero and we've still got the 0x prefix. + // Set endptr to point to 'x' and return + if (endptr) + *endptr = (char*)&str[1]; + return 0; + } + } + // if we're starting with zero, we're handling octal + else if (*str == '0') + { + if (base == 0 || base == 8) + base = 8; + str++; + } + + // if base is STILL zero, then we're dealing with decimal. + if (base == 0) base = 10; + + // keep reading digits + while (*str) + { + int digit = 0; + if (*str >= '0' && *str <= '9') + digit = *str - '0'; + else if (*str >= 'A' && *str <= 'Z') + digit = *str - 'A' + 10; + else if (*str >= 'a' && *str <= 'z') + digit = *str - 'a' + 10; + else + // we've reached the end. + break; + + // check in what situation we are about to overflow. + + // max without the last digit. + long long maxwld = max / base; + // if the value exceeds the max without the last digit already, this means that any digit we add will make it fail. + if (val > maxwld) + { + val = sign < 0 ? min : max; + errno = ERANGE; + if (endptr) *endptr = (char*)str; + return val; + } + // if it's equal + if (val == maxwld) + { + int digthresh = max % base; + // if we're in the negatives, bump it up + if (sign < 0) digthresh++; + + // if we're trying to tack on a digit bigger than the max's last digit, then we're going to overflow, so don't + if (digit > digthresh) + { + val = sign < 0 ? min : max; + errno = ERANGE; + if (endptr) *endptr = (char*)str; + return val; + } + } + + // if it's none of these, whatever digit we add will be valid. + val = val * base + digit; + + str++; + } + + if (endptr) + *endptr = (char*)str; + + return (long long) val * sign; +} + +unsigned long long int strtoull(const char* str, char ** endptr, int base) +{ + return strtoux(str, endptr, base, ULLONG_MAX); +} + +unsigned long int strtoul(const char* str, char ** endptr, int base) +{ + return (unsigned long int)strtoux(str, endptr, base, ULONG_MAX); +} + +long long int strtoll(const char* str, char ** endptr, int base) +{ + return strtox(str, endptr, base, LLONG_MAX); +} + +long int strtol(const char* str, char ** endptr, int base) +{ + return (long int)strtox(str, endptr, base, LONG_MAX); +} + +double ldexp(UNUSED double val, UNUSED int exp) +{ + // TODO + ASSERT(!"ldexp used!"); + return 0.0; +} + +double strtod(UNUSED const char* str, UNUSED char** endptr) +{ + // TODO + ASSERT(!"strtod used!"); + return 0.0; +} + +long double strtold(UNUSED const char* str, UNUSED char** endptr) +{ + // TODO + ASSERT(!"strtold used!"); + return 0.0; +} + +float strtof(UNUSED const char* str, UNUSED char** endptr) +{ + // TODO + ASSERT(!"strtof used!"); + return 0.0f; +} diff --git a/crt2/src/a_time.c b/crt2/src/a_time.c new file mode 100644 index 00000000..f098f1e3 --- /dev/null +++ b/crt2/src/a_time.c @@ -0,0 +1,141 @@ +// *************************************************************** +// a_video.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +static THREAD_LOCAL struct tm s_tm; + +void sleep(int ms) +{ + TmSleep(ms); +} + +// This function tries to approximate unix time the best that it can. +// This does not take into account leap seconds. Despite that, it matches the time +// functions on my system (used gmtime, matches exactly with a call to time(NULL)) +static int s_daysPerMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +int GetEpochTimeFromTimeStruct(TimeStruct* ts) +{ + int year = ts->year - 1970; + int days = 365 * year + 1; + + // (almost) every 4 years since 1972 are leap years. Count them in + // This should work again. (year - 2 + 4) / 4 = (year - 2) / 4 + 1. + int leapYears = (year + 2) / 4; + days += leapYears; + + // based on the month, determine the day + for (int month = 1; month < ts->month; month++) + { + days += s_daysPerMonth[month]; + if (month == 2 && ts->year % 4 == 0) // February -- leap year + days++; + } + + return days * 86400 + ts->hours * 3600 + ts->minutes * 60 + ts->seconds; +} + +int GetEpochTime() +{ + return GetEpochTimeFromTimeStruct(GetTime()); +} + +void GetHumanTimeFromEpoch(int utime, TimeStruct* pOut) +{ + // Separate the amount of days from the rest of the time. + int days = utime / 86400, secs = utime % 86400; + + // Turn the secs into hours, minutes and seconds. This is trivial. + pOut->hours = secs / 3600; + pOut->minutes = secs / 60 % 60; + pOut->seconds = secs % 60; + + // Get the year number. + int year = 1970; + while (days >= 365 + (year % 4 == 0)) + { + days -= 365 + (year % 4 == 0); + year++; + } + + // Get the month number. + int month = 1; + while (days >= s_daysPerMonth[month]) + { + days -= s_daysPerMonth[month]; + month++; + } + + pOut->day = days + 1; + pOut->month = month; + pOut->year = year; +} + +void StructTmToTimeStruct(TimeStruct* out, struct tm* in) +{ + out->seconds = in->tm_sec; + out->minutes = in->tm_min; + out->hours = in->tm_hour; + out->weekday = in->tm_wday; + out->day = in->tm_mday; + out->month = in->tm_mon; + out->year = in->tm_year; + out->statusA = out->statusB = 0; +} + +void TimeStructToStructTm(TimeStruct* in, struct tm* out) +{ + out->tm_sec = in->seconds; + out->tm_min = in->minutes; + out->tm_hour = in->hours; + out->tm_wday = in->weekday; + out->tm_mday = in->day; + out->tm_mon = in->month; + out->tm_year = in->year; + out->tm_gmtoff = 0; + out->tm_zone = "GMT"; +} + +double difftime(time_t a, time_t b) +{ + return a - b; +} + +time_t time(time_t* timer) +{ + time_t t = GetEpochTimeFromTimeStruct(GetTime()); + + if (timer) + *timer = t; + + return t; +} + +time_t mktime (struct tm * ptr) +{ + TimeStruct ts; + StructTmToTimeStruct(&ts, ptr); + return GetEpochTimeFromTimeStruct(&ts); +} + +struct tm* localtime_r(const time_t* timep, struct tm * result) +{ + TimeStruct ts; + GetHumanTimeFromEpoch(*timep, &ts); + TimeStructToStructTm(&ts, result); + return result; +} + +struct tm* localtime(const time_t* timep) +{ + return localtime_r(timep, &s_tm); +} diff --git a/crt2/src/a_ver.c b/crt2/src/a_ver.c new file mode 100644 index 00000000..49a221f4 --- /dev/null +++ b/crt2/src/a_ver.c @@ -0,0 +1,30 @@ +// *************************************************************** +// a_ver.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +char g_VersionString[10] = "VX.XX"; + +const char* GetVersionString() +{ + if (g_VersionString[1] == 'X') + { + int ver = NsGetVersion(); + //major version and minor version: + //NanoShell V1.00 (when that comes out) will have a version number of 100 + //Current version as of Feb 10,2022 (NanoShell V0.30) has a version code of 30. + //Some software may naively just put a 0 in the major version number, but + //we should expect an eventual V1.00 or more. + sprintf(g_VersionString, "V%d.%02d", ver/100, ver%100); + } + + return g_VersionString; +} diff --git a/crt2/src/a_video.c b/crt2/src/a_video.c new file mode 100644 index 00000000..bdfd82aa --- /dev/null +++ b/crt2/src/a_video.c @@ -0,0 +1,59 @@ +// *************************************************************** +// a_video.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +int GetWidth (Rectangle* rect) +{ + return rect->right - rect->left; +} + +int GetHeight (Rectangle* rect) +{ + return rect->bottom - rect->top; +} + +void VidDrawRectangle(unsigned color, Rectangle rect) +{ + VidDrawRect(color, rect.left, rect.top, rect.right, rect.bottom); +} + +void VidFillRectangle(unsigned color, Rectangle rect) +{ + VidFillRect(color, rect.left, rect.top, rect.right, rect.bottom); +} + +bool RectangleContains(Rectangle*r, Point*p) +{ + return (r->left <= p->x && r->right >= p->x && r->top <= p->y && r->bottom >= p->y); +} + +bool RectangleOverlap(Rectangle *r1, Rectangle *r2) +{ + return (r1->left <= r2->right && r1->right >= r2->left && r1->top <= r2->bottom && r1->bottom >= r2->top); +} + +void VidSetClipRect(Rectangle* x) +{ + if (x) + { + VidSetClipRectP(*x); + } + else + { + Rectangle r; + r.left = -1; + r.top = -1; + r.right = -1; + r.bottom = -1; + VidSetClipRectP(r); + } +} diff --git a/crt2/src/a_window.c b/crt2/src/a_window.c new file mode 100644 index 00000000..f4cf90a8 --- /dev/null +++ b/crt2/src/a_window.c @@ -0,0 +1,17 @@ +// *************************************************************** +// a_window.c - Creation date: 01/09/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +void _I_CloseOpenWindows() +{ + //... +} diff --git a/crt2/src/calldefs.h b/crt2/src/calldefs.h new file mode 100644 index 00000000..fffabd15 --- /dev/null +++ b/crt2/src/calldefs.h @@ -0,0 +1,606 @@ +// *************************************************************** +// calldefs.h - Creation date: 21/04/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +// Video Call Functions: +CALL (GetScreenSizeX, VID_GET_SCREEN_WIDTH, int) + RARGS() +CALL_END +CALL (GetScreenSizeY, VID_GET_SCREEN_HEIGHT, int) + RARGS() +CALL_END +CALL (VidPlotPixel, VID_PLOT_PIXEL, void, unsigned x, unsigned y, unsigned color) + SARGS(x,y,color) +CALL_END +CALL (VidFillScreen, VID_FILL_SCREEN, void, unsigned color) + SARGS(color) +CALL_END +CALL (VidDrawVLine, VID_DRAW_V_LINE, void, unsigned color, int top, int bottom, int x) + SARGS(color,top,bottom,x) +CALL_END +CALL (VidDrawHLine, VID_DRAW_H_LINE, void, unsigned color, int left, int right, int y) + SARGS(color,left,right,y) +CALL_END +CALL (VidDrawLine, VID_DRAW_LINE, void, unsigned p, int x1, int y1, int x2, int y2) + SARGS(p,x1,y1,x2,y2) +CALL_END +CALL (VidSetFont, VID_SET_FONT, void, unsigned fontType) + SARGS(fontType) +CALL_END +CALL (VidPlotChar, VID_PLOT_CHAR, void, char c,unsigned ox,unsigned oy,unsigned colorFg,unsigned colorBg) + SARGS(c,ox,oy,colorFg,colorBg) +CALL_END +CALL (VidBlitImage, VID_BLIT_IMAGE, void, Image*pImage, int x, int y) + SARGS(pImage,x,y) +CALL_END +CALL (VidTextOut, VID_TEXT_OUT, void, const char* pText, unsigned ox, unsigned oy, unsigned colorFg, unsigned colorBg) + SARGS(pText,ox,oy,colorFg,colorBg) +CALL_END +CALL (VidTextOutInternal, VID_TEXT_OUT_INT, void, const char* pText, unsigned ox, unsigned oy, unsigned colorFg, unsigned colorBg, bool doNotActuallyDraw, int* width, int* height) + SARGS(pText,ox,oy,colorFg,colorBg,doNotActuallyDraw,width,height) +CALL_END +CALL (VidDrawText, VID_DRAW_TEXT, void, const char* pText, Rectangle rect, unsigned drawFlags, unsigned colorFg, unsigned colorBg) + SARGS(pText, rect, drawFlags, colorFg, colorBg) +CALL_END +CALL (VidShiftScreen, VID_SHIFT_SCREEN, void, int amount) + SARGS(amount) +CALL_END +CALL (VidFillRect, VID_FILL_RECT, void, unsigned color, int left, int top, int right, int bottom) + SARGS(color,left,top,right,bottom) +CALL_END +CALL (VidDrawRect, VID_DRAW_RECT, void, unsigned color, int left, int top, int right, int bottom) + SARGS(color,left,top,right,bottom) +CALL_END +CALL (VidFillRectHGradient, VID_FILL_RECT_H_GRADIENT, void, unsigned colorL, unsigned colorR, int left, int top, int right, int bottom) + SARGS(colorL,colorR,left,top,right,bottom) +CALL_END +CALL (VidFillRectVGradient, VID_FILL_RECT_V_GRADIENT, void, unsigned colorU, unsigned colorD, int left, int top, int right, int bottom) + SARGS(colorU,colorD,left,top,right,bottom) +CALL_END + +// Window Call Functions: +CALL (CreateWindow, WIN_CREATE, Window*, const char*pTitle, int xPos, int yPos, int xSize, int ySize, WindowProc proc, int flags) + RARGS(pTitle, xPos, yPos, xSize, ySize, proc, flags) +CALL_END + +CALL (DestroyWindow, WIN_DESTROY, void, Window* pWindow) + SARGS(pWindow) +CALL_END + +CALL (DefaultWindowProc, WIN_DEFAULT_PROC, void, Window* pWindow, int messageType, int parm1, int parm2) + SARGS(pWindow, messageType, parm1, parm2) +CALL_END + +CALL (MessageBox, WIN_MESSAGE_BOX, int, Window* pWindow, const char* pText, const char* pCaption, uint32_t type) + RARGS(pWindow, pText, pCaption, type) +CALL_END + +CALL (AddControl, WIN_ADD_CONTROL, int, Window* pWindow, int type, Rectangle rect, const char* text, int comboID, int p1, int p2) + RARGS(pWindow, type, rect, text, comboID, p1, p2) +CALL_END + +CALL (HandleMessages, WIN_HANDLE_MESSAGES, bool, Window* pWindow) + RARGS(pWindow) +CALL_END + +// Window stuff +CALL (RequestRepaint, WIN_REQUEST_REPAINT, void, Window* pWindow) + SARGS(pWindow) +CALL_END +CALL (SetLabelText, WIN_SET_LABEL_TEXT, void, Window* pWindow, int comboID, const char* pText) + SARGS(pWindow, comboID, pText) +CALL_END +CALL (AddMenuBarItem, WIN_ADD_MENUBAR_ITEM, void, Window* pWindow, int menuBarControlId, int comboIdTo, int comboIdAs, const char* pText) + SARGS(pWindow, menuBarControlId, comboIdTo, comboIdAs, pText) +CALL_END +CALL (SetScrollBarMin, WIN_SET_SCROLL_BAR_MIN, void, Window *pWindow, int comboID, int min) + SARGS(pWindow, comboID, min) +CALL_END +CALL (SetScrollBarMax, WIN_SET_SCROLL_BAR_MAX, void, Window *pWindow, int comboID, int max) + SARGS(pWindow, comboID, max) +CALL_END +CALL (SetScrollBarPos, WIN_SET_SCROLL_BAR_POS, void, Window *pWindow, int comboID, int pos) + SARGS(pWindow, comboID, pos) +CALL_END +CALL (GetScrollBarPos, WIN_GET_SCROLL_BAR_POS, int, Window *pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL (AddElementToList, WIN_ADD_ELEM_TO_LIST, void, Window* pWindow, int comboID, const char* pText, int optionalIcon) + SARGS(pWindow, comboID, pText, optionalIcon) +CALL_END +CALL (RemoveElementFromList, WIN_REM_ELEM_FROM_LIST, void, Window* pWindow, int comboID, int elemIndex) + SARGS(pWindow, comboID, elemIndex) +CALL_END +CALL (GetElementStringFromList, WIN_GET_ELEM_STR_FROM_LIST, const char*, Window* pWindow, int comboID, int elemIndex) + RARGS(pWindow, comboID, elemIndex) +CALL_END +CALL (ResetList, WIN_CLEAR_LIST, void, Window* pWindow, int comboID) + SARGS(pWindow, comboID) +CALL_END + +// Console I/O +CALLI(PutString, CON_PUTSTRING, void, const char* pText) + SARGS(pText) +CALL_END +CALLI(ReadChar, CON_READCHAR, char, void) + RARGS() +CALL_END +CALLI(ReadString, CON_READSTR, void, char* pOutBuffer, int maxSize) + SARGS(pOutBuffer, maxSize) +CALL_END + +// Memory allocation +CALLI(AllocateDebug, MM_ALLOCATE_D, void*, size_t size, const char* callerFile, int callerLine) + RARGS(size, callerFile, callerLine) +CALL_END +CALLI(Free, MM_FREE, void, void* ptr) + SARGS(ptr) +CALL_END +CALLI(MmDebugDump, MM_DEBUG_DUMP, void, void) + SARGS() +CALL_END + +// File I/O +CALLI(FiOpenDebug, FI_OPEN_D, int /* file descriptor or errcode if negative */, const char* pFileName, int oFlag, const char* pSrcFile, int nSrcLine) + RARGS(pFileName, oFlag, pSrcFile, nSrcLine) +CALL_END +CALLI(FiClose, FI_CLOSE, int /* err code */, int fd) + RARGS(fd) +CALL_END +CALLI(FiRead, FI_READ, int /* num bytes read */, int fd, void* pBuf, int nBytes) + RARGS(fd, pBuf, nBytes) +CALL_END +CALLI(FiWrite, FI_WRITE, int /* num bytes read */, int fd, void* pBuf, int nBytes) + RARGS(fd, pBuf, nBytes) +CALL_END +CALLI(FiTell, FI_TELL, int /* num bytes into file */, int fd) + RARGS(fd) +CALL_END +CALLI(FiTellSize, FI_TELLSIZE, int /* num bytes into file */, int fd) + RARGS(fd) +CALL_END +CALLI(FiSeek, FI_SEEK, int /* err code */, int fd, int offset, int whence) + RARGS(fd, offset, whence) +CALL_END + +CALL (SetHugeLabelText, WIN_SET_HUGE_LABEL_TEXT, void, Window* pWindow, int comboID, const char* pText) + SARGS(pWindow, comboID, pText) +CALL_END +CALL (SetTextInputText, WIN_SET_INPUT_TEXT_TEXT, void, Window* pWindow, int comboID, const char* pText) + SARGS(pWindow, comboID, pText) +CALL_END +CALL (SetWindowIcon, WIN_SET_WINDOW_ICON, void, Window* pWindow, int iconID) + SARGS(pWindow, iconID) +CALL_END +CALL (SetWindowTitle, WIN_SET_WINDOW_TITLE, void, Window* pWindow, const char* pText) + SARGS(pWindow, pText) +CALL_END + +CALL (GetTickCount, TM_GET_TICK_COUNT, int, void) + RARGS() +CALL_END +CALL (GetTime, TM_GET_TIME, TimeStruct*, void) + RARGS() +CALL_END +CALL (GetCpuType, CPU_GET_TYPE, const char*, void) + RARGS() +CALL_END +CALL (GetCpuName, CPU_GET_NAME, const char*, void) + RARGS() +CALL_END + +CALL (GetConsole, CON_GET_CURRENT_CONSOLE, void*, void) + RARGS() +CALL_END + +CALL (RegisterEvent, WIN_REGISTER_EVENT, void, Window* pWindow, short evType, int parm1, int parm2) + SARGS(pWindow, evType, parm1, parm2) +CALL_END +CALL (RegisterEventInsideWndProc, WIN_REGISTER_EVENT2, void, Window* pWindow, short evType, int parm1, int parm2) + SARGS(pWindow, evType, parm1, parm2) +CALL_END + +CALL (VidBlitImageResize, VID_BLIT_IMAGE_RESIZE, void, Image*pImage, int x, int y, int width, int height) + SARGS(pImage,x,y, width, height) +CALL_END + +CALL (TmSleep, TM_SLEEP, void, int ms) + SARGS(ms) +CALL_END + +CALL (SetIcon, WIN_SET_ICON, void, Window* pWindow, int comboID, int icon) + SARGS(pWindow,comboID,icon) +CALL_END + +CALL (NsGetVersion, NS_GET_VERSION, int, void) + RARGS() +CALL_END + +CALL (GetThemingParameter, WIN_GET_THEME_PARM, uint32_t, int type) + RARGS(type) +CALL_END +CALL (SetThemingParameter, WIN_SET_THEME_PARM, void, int type, uint32_t parm) + SARGS(type, parm) +CALL_END + +// Calls V1.3 +CALL (CheckboxSetChecked, WIN_CHECKBOX_SET_CHECKED, void, Window* pWindow, int comboID, bool checked) + SARGS(pWindow, comboID, checked) +CALL_END +CALL (CheckboxGetChecked, WIN_CHECKBOX_GET_CHECKED, bool, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL (TextInputQueryDirtyFlag, WIN_TEXT_INPUT_QUERY_DIRTY_FLAG, bool, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL (TextInputClearDirtyFlag, WIN_TEXT_INPUT_CLEAR_DIRTY_FLAG, void, Window* pWindow, int comboID) + SARGS(pWindow, comboID) +CALL_END +CALL (TextInputGetRawText, WIN_TEXT_INPUT_GET_RAW_TEXT, const char*, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALLI(CcRunCCode, CC_RUN_C_CODE, int, const char* pData, int length) + RARGS(pData, length) +CALL_END +CALLI(FiUnlinkFile, FI_REMOVE_FILE, int, const char* pName) + RARGS(pName) +CALL_END +CALL (AddControlEx, WIN_ADD_CONTROL_EX, int, Window* pWindow, int type, int amode, Rectangle rect, const char* text, int comboID, int p1, int p2) + RARGS(pWindow, type, amode, rect, text, comboID, p1, p2) +CALL_END +CALL (RequestRepaintNew, WIN_REQUEST_REPAINT_NEW, void, Window* pWindow) + SARGS(pWindow) +CALL_END +CALL (ShellAbout, WIN_SHELL_ABOUT, void, const char* text, int icon) + SARGS(text, icon) +CALL_END +CALL (InputBox, WIN_INPUT_BOX, char*, Window* pWindow, const char* pPrompt, const char* pCaption, const char* pDefaultText) + RARGS(pWindow, pPrompt, pCaption, pDefaultText) +CALL_END +CALL (ColorInputBox, WIN_COLOR_BOX, uint32_t, Window* pWindow, const char* pPrompt, const char* pCaption) + RARGS(pWindow, pPrompt, pCaption) +CALL_END +CALL (PopupWindow, WIN_POPUP_WINDOW, void, Window* pWindow, const char* newWindowTitle, int newWindowX, int newWindowY, int newWindowW, int newWindowH, WindowProc newWindowProc, int newFlags) + SARGS(pWindow, newWindowTitle, newWindowX, newWindowY, newWindowW, newWindowH, newWindowProc, newFlags) +CALL_END +CALL (FilePickerBox, WIN_FILE_CHOOSE_BOX, char *, Window * pWindow, const char * prompt, const char * caption, const char * default_text) + RARGS(pWindow, prompt, caption, default_text) +CALL_END + +// Calls V1.4 +CALL (VidSetVbeData, VID_SET_VBE_DATA, VBEData*, VBEData* pData) + RARGS(pData) +CALL_END +CALLI(FiOpenDirD, FI_OPEN_DIR_D, int, const char* pFileName, const char* srcFile, int srcLine) + RARGS(pFileName, srcFile, srcLine) +CALL_END +CALLI(FiCloseDir, FI_CLOSE_DIR, int, int dd) + RARGS(dd) +CALL_END +CALLI(FiReadDir, FI_READ_DIR, int, DirEnt* p, int dd) + RARGS(p, dd) +CALL_END +CALLI(FiSeekDir, FI_SEEK_DIR, int, int dd, int loc) + RARGS(dd, loc) +CALL_END +CALLI(FiRewindDir, FI_REWIND_DIR, int, int dd) + RARGS(dd) +CALL_END +CALLI(FiTellDir, FI_TELL_DIR, int, int dd) + RARGS(dd) +CALL_END +CALLI(FiStatAt, FI_STAT_AT, int, int dd, const char *pfn, StatResult* pres) + RARGS(dd, pfn, pres) +CALL_END +CALLI(FiStat, FI_STAT, int, const char *pfn, StatResult* pres) + RARGS(pfn, pres) +CALL_END +CALL (FiGetCwd, FI_GET_CWD, const char*, void) + RARGS() +CALL_END +CALLI(FiChDir, FI_CHANGE_DIR, int, const char* p) + RARGS(p) +CALL_END +CALL (GetWidgetEventHandler, WIN_GET_WIDGET_EVENT_HANDLER, WidgetEventHandler, int type) + RARGS(type) +CALL_END +CALL (SetWidgetEventHandler, WIN_SET_WIDGET_EVENT_HANDLER, void, Window *pWindow, int comboID, WidgetEventHandler handler) + SARGS(pWindow, comboID, handler) +CALL_END +CALL (SetImageCtlMode, WIN_SET_IMAGE_CTL_MODE, void, Window *pWindow, int comboID, int mode) + SARGS(pWindow, comboID, mode) +CALL_END +CALL (SetImageCtlColor, WIN_SET_IMAGE_CTL_COLOR, void, Window *pWindow, int comboID, uint32_t color) + SARGS(pWindow, comboID, color) +CALL_END +CALL (SetImageCtlCurrentImage, WIN_SET_IMAGE_CTL_IMAGE, void, Window *pWindow, int comboID, Image* pImage) + SARGS(pWindow, comboID, pImage) +CALL_END +CALL (GetImageCtlCurrentImage, WIN_GET_IMAGE_CTL_IMAGE, Image*, Window *pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL (ImageCtlZoomToFill, WIN_IMAGE_CTL_ZOOM_TO_FILL, void, Window *pWindow, int comboID) + SARGS(pWindow, comboID) +CALL_END +CALL (SetFocusedControl, WIN_SET_FOCUSED_CONTROL, void, Window *pWindow, int comboID) + SARGS(pWindow, comboID) +CALL_END +CALL (PopupWindowEx, WIN_POPUP_WINDOW_EX, void, const char* newWindowTitle, int newWindowX, int newWindowY, int newWindowW, int newWindowH, WindowProc newWindowProc, int newFlags, void* newData) + SARGS(newWindowTitle, newWindowX, newWindowY, newWindowW, newWindowH, newWindowProc, newFlags, newData) +CALL_END +CALL (ErrNoStr, ERR_GET_STRING, const char*, int errNum) + RARGS(errNum) +CALL_END +CALL (GetMousePos, VID_GET_MOUSE_POS, Point, void) + RARGS() +CALL_END +CALL (VidSetClipRectP, VID_SET_CLIP_RECT, void, Rectangle r) + SARGS(r) +CALL_END +CALL (CbClear, CB_CLEAR, void, void) + SARGS() +CALL_END +CALL (CbCopyText, CB_COPY_TEXT, bool, const char *pText) + RARGS(pText) +CALL_END +CALL (CbCopyBlob, CB_COPY_BLOB, bool, void* pData, size_t sz) + RARGS(pData, sz) +CALL_END +CALL (CbGetCurrentVariant, CB_GET_CURRENT_VARIANT, ClipboardVariant*, void) + RARGS() +CALL_END +CALL (CbRelease, CB_RELEASE, void, ClipboardVariant* pVar) + SARGS(pVar) +CALL_END + +// Calls V1.5 +CALL (RenderIcon, VID_RENDER_ICON, void, int type, int x, int y) + SARGS(type, x, y) +CALL_END +CALL (RenderIconOutline, VID_RENDER_ICON_OUTLINE, void, int type, int x, int y, uint32_t color) + SARGS(type, x, y, color) +CALL_END +CALL (RenderIconForceSize, VID_RENDER_ICON_SIZE, void, int type, int x, int y, int size) + SARGS(type, x, y, size) +CALL_END +CALL (RenderIconForceSizeOutline, VID_RENDER_ICON_SIZE_OUTLINE, void, int type, int x, int y, int size, uint32_t color) + SARGS(type, x, y, size, color) +CALL_END +CALL (GetRandom, TM_GET_RANDOM, int, void) + RARGS() +CALL_END + +// Calls V1.6 +CALLI(ReAllocateDebug, MM_REALLOCATE_D, void*, void* o, size_t s, const char* f, int l) + RARGS(o, s, f, l) +CALL_END +CALL (ShellExecute, SH_EXECUTE, int, const char* p) + RARGS(p) +CALL_END +CALL (ShellExecuteResource, SH_EXECUTE_RESOURCE, int, const char* p) + RARGS(p) +CALL_END + +// Calls V1.7 +CALL (MemoryMap, MM_MAP_MEMORY_USER, int, void* pMem, size_t nSize, int pFlags, int mFlags, int fd, size_t off, void **pOut) + RARGS(pMem, nSize, pFlags, mFlags, fd, off, pOut) +CALL_END +CALL (MemoryUnmap, MM_UNMAP_MEMORY_USER, int, void* pMem, size_t nSize) + RARGS(pMem, nSize) +CALL_END + +// Calls V1.8 +CALLI(FiRename, FI_RENAME, int, const char * pfnOld, const char * pfnNew) + RARGS(pfnOld, pfnNew) +CALL_END +CALLI(FiMakeDir, FI_MAKE_DIR, int, const char * path) + RARGS(path) +CALL_END +CALLI(FiRemoveDir, FI_REMOVE_DIR, int, const char * path) + RARGS(path) +CALL_END +CALLI(FiCreatePipe, FI_CREATE_PIPE, int, const char * friendlyName, int fds[2], int oflags) + RARGS(friendlyName, fds, oflags) +CALL_END +CALLI(FiIoControl, FI_IO_CONTROL, int, int fd, unsigned long request, void * argp) + RARGS(fd, request, argp) +CALL_END +CALL (CallControlCallback, WIN_CALL_CTL_CALLBACK, void, Window * window, int comboid, int event, int parm1, int parm2) + SARGS(window, comboid, event, parm1, parm2) +CALL_END +CALL (TextInputSetMode, WIN_TEXT_INPUT_SET_MODE, void, Window* pWindow, int comboID, int mode) + SARGS(pWindow, comboID, mode) +CALL_END + +// Calls V1.9 +CALL(GetScrollBarMin, WIN_GET_SCROLL_BAR_MIN, int, Window *pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(GetScrollBarMax, WIN_GET_SCROLL_BAR_MAX, int, Window *pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(GetSelectedIndexList, WIN_GET_SEL_INDEX_LIST, int, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(SetSelectedIndexList, WIN_SET_SEL_INDEX_LIST, void, Window* pWindow, int comboID, int index) + SARGS(pWindow, comboID, index) +CALL_END +CALL(GetSelectedIndexTable, WIN_GET_SEL_INDEX_TABLE, int, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(SetSelectedIndexTable, WIN_SET_SEL_INDEX_TABLE, void, Window* pWindow, int comboID, int selectedIndex) + SARGS(pWindow, comboID, selectedIndex) +CALL_END +CALL(GetScrollTable, WIN_GET_SCROLL_TABLE, int, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(SetScrollTable, WIN_SET_SCROLL_TABLE, void, Window* pWindow, int comboID, int scroll) + SARGS(pWindow, comboID, scroll) +CALL_END +CALL(AddTableRow, WIN_ADD_TABLE_ROW, void, Window* pWindow, int comboID, const char* pText[], int optionalIcon) + SARGS(pWindow, comboID, pText, optionalIcon) +CALL_END +CALL(AddTableColumn, WIN_ADD_TABLE_COLUMN, void, Window* pWindow, int comboID, const char* pText, int width) + SARGS(pWindow, comboID, pText, width) +CALL_END +CALL(GetRowStringsFromTable, WIN_GET_ROW_STRINGS_FROM_TABLE, bool, Window* pWindow, int comboID, int index, const char * output[]) + RARGS(pWindow, comboID, index, output) +CALL_END +CALL(RemoveRowFromTable, WIN_REMOVE_ROW_FROM_TABLE, void, Window* pWindow, int comboID, int elementIndex) + SARGS(pWindow, comboID, elementIndex) +CALL_END +CALL(ResetTable, WIN_RESET_TABLE, void, Window* pWindow, int comboID) + SARGS(pWindow, comboID) +CALL_END + +// Calls V2.0 +CALL(VidReadPixel, VID_READ_PIXEL, unsigned, unsigned x, unsigned y) + RARGS(x,y) +CALL_END +CALL(CfgGetString, CFG_GET_STRING, const char*, const char* parm) + RARGS(parm) +CALL_END +CALL(VidGetVbeData, VID_GET_VBE_DATA, VBEData*, void) + RARGS() +CALL_END + +// Calls V2.1 +CALL(GetWindowTitle, WIN_GET_WINDOW_TITLE, const char*, Window* pWindow) + RARGS(pWindow) +CALL_END +CALL(GetWindowData, WIN_GET_WINDOW_DATA, void*, Window* pWindow) + RARGS(pWindow) +CALL_END +CALL(SetWindowData, WIN_SET_WINDOW_DATA, void, Window* pWindow, void* ptr) + SARGS(pWindow, ptr) +CALL_END +CALL(GetWindowRect, WIN_GET_WINDOW_RECT, void, Window* pWindow, Rectangle* pRectOut) + SARGS(pWindow, pRectOut) +CALL_END +CALL(CallWindowCallbackAndControls, WIN_CALL_CALLBACK_AND_CTLS, void, int et, int p1, int p2) + SARGS(et, p1, p2) +CALL_END +CALL(ChangeCursor, WIN_CHANGE_CURSOR, void, Window* pWindow, int cursorID) + SARGS(pWindow, cursorID) +CALL_END +CALL(SetWindowFlags, WIN_SET_FLAGS, void, Window* pWindow, int flags) + SARGS(pWindow, flags) +CALL_END +CALL(GetWindowFlags, WIN_GET_FLAGS, int, Window* pWindow) + RARGS(pWindow) +CALL_END + +// Calls V2.2 +CALL(SetMousePos, VID_SET_MOUSE_POS, void, int newX, int newY) + SARGS(newX, newY) +CALL_END + +CALL(AddTimer, WIN_ADD_TIMER, int, Window* pWindow, int frequency, int event) + RARGS(pWindow, frequency, event) +CALL_END + +CALL(DisarmTimer, WIN_DISARM_TIMER, void, Window* pWindow, int timerID) + SARGS(pWindow, timerID) +CALL_END + +CALL(ChangeTimer, WIN_CHANGE_TIMER, void, Window* pWindow, int timerID, int newFreq, int newEvent) + SARGS(pWindow, timerID, newFreq, newEvent) +CALL_END + +// Calls V2.3 +CALL(UploadCursor, WIN_UPLOAD_CURSOR, int, Image * pImage, int xOff, int yOff) + RARGS(pImage, xOff, yOff) +CALL_END +CALL(ReleaseCursor, WIN_UPLOAD_CURSOR, void, int cursorID) + SARGS(cursorID) +CALL_END +CALL(SetListItemText, WIN_SET_LIST_ITEM_TEXT, void, Window* pWindow, int comboID, int index, int icon, const char * pText) + SARGS(pWindow, comboID, index, icon, pText) +CALL_END +CALL(GetIconImage, WIN_GET_ICON_IMAGE, Image*, int iconID, int size) + RARGS(iconID, size) +CALL_END +CALL(GetResource, RST_LOOK_UP_RESOURCE, Resource*, int resID) + RARGS(resID) +CALL_END +CALL(SetControlDisabled, WIN_SET_CONTROL_DISABLED, void, Window* pWindow, int comboID, bool flag) + SARGS(pWindow, comboID, flag) +CALL_END +CALL(SetControlFocused, WIN_SET_CONTROL_FOCUSED, void, Window* pWindow, int comboID, bool flag) + SARGS(pWindow, comboID, flag) +CALL_END +CALL(SetControlVisible, WIN_SET_CONTROL_VISIBLE, void, Window* pWindow, int comboID, bool flag) + SARGS(pWindow, comboID, flag) +CALL_END +CALL(ProgBarSetProgress, WIN_PROG_BAR_SET_PROGRESS, void, Window* pWindow, int comboID, int x) + SARGS(pWindow, comboID, x) +CALL_END +CALL(ProgBarSetMaxProg, WIN_PROG_BAR_SET_MAX_PROG, void, Window* pWindow, int comboID, int x) + SARGS(pWindow, comboID, x) +CALL_END + +// Calls V2.4 +CALL(ComboBoxAddItem, WIN_COMBO_BOX_ADD_ITEM, void, Window* pWindow, int comboID, const char* item, int itemID, int iconID) + SARGS(pWindow, comboID, item, itemID, iconID) +CALL_END +CALL(ComboBoxGetSelectedItemID, WIN_COMBO_BOX_GET_SELECTED_ITEM, int, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(ComboBoxSetSelectedItemID, WIN_COMBO_BOX_SET_SELECTED_ITEM, void, Window* pWindow, int comboID, int itemID) + SARGS(pWindow, comboID, itemID) +CALL_END +CALL(ComboBoxClearItems, WIN_COMBO_BOX_CLEAR_ITEMS, void, Window* pWindow, int comboID) + SARGS(pWindow, comboID) +CALL_END +CALL(IsControlFocused, WIN_IS_CONTROL_FOCUSED, bool, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(IsControlDisabled, WIN_IS_CONTROL_DISABLED, bool, Window* pWindow, int comboID) + RARGS(pWindow, comboID) +CALL_END +CALL(TextInputSetFont, WIN_TEXT_INPUT_SET_FONT, void, Window* pWindow, int comboID, unsigned font) + SARGS(pWindow, comboID, font) +CALL_END +CALL(TextInputRequestCommand, WIN_TEXT_INPUT_REQUEST_COMMAND, void, Window *pWindow, int comboID, int command, void* parm) + SARGS(pWindow, comboID, command, parm) +CALL_END + +// Calls V2.5 +CALL(DrawEdge, WIN_DRAW_EDGE, void, Rectangle rect, int style, unsigned bg) + SARGS(rect, style, bg) +CALL_END +CALL(DrawArrow, WIN_DRAW_ARROW, void, Rectangle rect, eArrowType arrowType, int flags, unsigned color) + SARGS(rect, arrowType, flags, color) +CALL_END +CALL(TabViewAddTab, WIN_TAB_VIEW_ADD_TAB, void, Window* pWindow, int comboID, int tabID, const char* pTabText, int tabWidth) + SARGS(pWindow, comboID, tabID, pTabText, tabWidth) +CALL_END +CALL(TabViewRemoveTab, WIN_TAB_VIEW_REMOVE_TAB, void, Window* pWindow, int comboID, int tabID) + SARGS(pWindow, comboID, tabID) +CALL_END +CALL(TabViewClearTabs, WIN_TAB_VIEW_REMOVE_TAB, void, Window* pWindow, int comboID) + SARGS(pWindow, comboID) +CALL_END +CALL(SpawnMenu, WIN_SPAWN_MENU, Window*, Window* pParentWindow, WindowMenu* pRoot, int x, int y) + RARGS(pParentWindow, pRoot, x, y) +CALL_END +CALL(KbGetKeyState, KB_GET_KEY_STATE, KeyState, unsigned char keycode) + RARGS(keycode) +CALL_END +CALL(LockAcquire, LCK_ACQUIRE, void, SafeLock* ptr) + SARGS(ptr) +CALL_END +CALL(LockFree, LCK_FREE, void, SafeLock* ptr) + SARGS(ptr) +CALL_END + +// Calls V2.6 +CALLI(FiLinkStat, FI_STAT_LINK, int, const char *pfn, StatResult* pres) + RARGS(pfn, pres) +CALL_END diff --git a/crt2/src/calls.c b/crt2/src/calls.c new file mode 100644 index 00000000..c8a6af9b --- /dev/null +++ b/crt2/src/calls.c @@ -0,0 +1,62 @@ +// *************************************************************** +// calls.c - Creation date: 21/04/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" + +#define WINDOW_CALL_BASE 0xc0007c00 + +// Type Definitions. +#define CALL(funcName, funcIndex, retType, ...)\ + typedef retType(* P_I_ ## funcName) (__VA_ARGS__); +#define CALLI(funcName, funcIndex, retType, ...)\ + typedef retType(* P_I_ ## funcName) (__VA_ARGS__); +#define RARGS(...) +#define SARGS(...) +#define CALL_END + +#include "calldefs.h" + +#undef CALL +#undef CALLI +#undef RARGS +#undef SARGS +#undef CALL_END + +// Wrapper function definitions. +// CALL = Function that's available for use. +// CALLI = Internal function that shouldn't be used. +#define CALL(funcName, funcIndex, retType, ...)\ + retType funcName (__VA_ARGS__)\ + {\ + *((uint32_t*)(WINDOW_CALL_BASE + 0xFC)) = funcIndex;\ + P_I_ ## funcName p_func = (P_I_ ## funcName)WINDOW_CALL_BASE;\ + +#define CALLI(funcName, funcIndex, retType, ...)\ + retType _I_ ## funcName (__VA_ARGS__)\ + {\ + *((uint32_t*)(WINDOW_CALL_BASE + 0xFC)) = funcIndex;\ + P_I_ ## funcName p_func = (P_I_ ## funcName)WINDOW_CALL_BASE;\ + +#define RARGS(...)\ + return p_func (__VA_ARGS__);\ + } +#define SARGS(...)\ + p_func (__VA_ARGS__);\ + } +#define CALL_END //empty, use if needed + +#include "calldefs.h" + +#undef CALL +#undef RARGS +#undef SARGS +#undef CALL_END + + diff --git a/crt2/src/crt0.asm b/crt2/src/crt0.asm new file mode 100644 index 00000000..3131215a --- /dev/null +++ b/crt2/src/crt0.asm @@ -0,0 +1,94 @@ +; NanoShell C-Runtime basics +; Copyright (C) 2022 iProgramInCpp + +BITS 32 + +SECTION .data + +; The way we 'exit' on this is a bit unconventional. We do not have a syscall +; to exit, instead, returning from the entry point actually kills the process/thread. +; This is why we need to backup the EBP and ESP, so that we can return properly in +; case of an exit(). +EbpBackup DD 1 +EspBackup DD 1 + +SECTION .text + +; C-main function +EXTERN _CEntry +; Internal library cleanup functions +EXTERN _I_FreeEverything +EXTERN _I_CloseOpenFiles +EXTERN _I_Setup + +; Force exit function `void exit(int code)` +GLOBAL exit +; Internal entry point +GLOBAL _NsStart + +exit: + push ebp + mov ebp, esp + + ; Call internal cleanup functions + call _I_CloseOpenFiles + call _I_FreeEverything + + mov eax, [ebp + 8] + jmp _NsExitPoint ;Nothing to lose + +_NsStart: + mov [EspBackup], esp + mov [EbpBackup], ebp + + push ebp + mov ebp, esp + + mov eax, [ebp + 8] + + push eax + call _CEntry + ; no return + +_NsExitPoint: + mov esp, [EspBackup] + mov ebp, [EbpBackup] + + ret ; return to kernel + +; Well, this is basically the same thing, but a bit more diverse +; https://github.com/jezze/subc +global SetJump +global setjmp +global LongJump +global longjmp +SetJump: +setjmp: + mov edx, [esp + 4] + mov [edx], esp + add dword [edx], 4 + mov [edx + 4], ebp + mov eax, [esp] + mov [edx + 8], eax + mov [edx + 12], ebx + mov [edx + 16], esi + mov [edx + 20], edi + xor eax, eax + retn + +LongJump: +longjmp: + mov eax, [esp + 8] + or eax, eax + ; the spec says to return 1 if there's no 'val' passed into longjmp(). + jnz .increment + inc eax +.increment: + mov edx, [esp + 4] + mov esp, [edx] + mov ebp, [edx + 4] + mov ebx, [edx + 12] + mov esi, [edx + 16] + mov edi, [edx + 20] + mov edx, [edx + 8] + jmp edx diff --git a/crt2/src/crtinternal.h b/crt2/src/crtinternal.h new file mode 100644 index 00000000..63390cb3 --- /dev/null +++ b/crt2/src/crtinternal.h @@ -0,0 +1,32 @@ +// *************************************************************** +// crtinternal.h - Creation date: 21/04/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#ifndef _CRTINTERNAL_H +#define _CRTINTERNAL_H + +#define CALL(funcName, funcIndex, retType, ...) retType funcName (__VA_ARGS__); +#define CALLI(funcName, funcIndex, retType, ...) retType _I_ ## funcName (__VA_ARGS__); +#define RARGS(...) +#define SARGS(...) +#define CALL_END + +#include "calldefs.h" + +#undef CALL +#undef CALLI +#undef RARGS +#undef SARGS +#undef CALL_END + +// currently, this does nothing. However, it's safe to say we will need it when we +// move to a multithreaded version of this libc +#define THREAD_LOCAL + +#endif//_CRTINTERNAL_H \ No newline at end of file diff --git a/crt2/src/crtlib.h b/crt2/src/crtlib.h new file mode 100644 index 00000000..66eaaff4 --- /dev/null +++ b/crt2/src/crtlib.h @@ -0,0 +1,309 @@ +// *************************************************************** +// crtlib.h - Creation date: 21/04/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#ifndef _CRTLIB_H +#define _CRTLIB_H + +#include "../include/nsstructs.h" + +#define WCALL_VERSION 26 +enum +{ + // System Calls V1.0 + CALL_NOTHING, + //Video Driver calls: + VID_GET_SCREEN_WIDTH, + VID_GET_SCREEN_HEIGHT, + VID_PLOT_PIXEL, + VID_FILL_SCREEN, //Actually fills the context, not the screen + VID_DRAW_H_LINE, + VID_DRAW_V_LINE, + VID_DRAW_LINE, + VID_SET_FONT, + VID_PLOT_CHAR, + VID_BLIT_IMAGE, + VID_TEXT_OUT, + VID_TEXT_OUT_INT, + VID_DRAW_TEXT, + VID_SHIFT_SCREEN, + VID_FILL_RECT, + VID_DRAW_RECT, + VID_FILL_RECT_H_GRADIENT, + VID_FILL_RECT_V_GRADIENT, + + //Window Manager calls: + WIN_CREATE, + WIN_HANDLE_MESSAGES, + WIN_DEFAULT_PROC, + WIN_DESTROY, + WIN_MESSAGE_BOX, + WIN_ADD_CONTROL, + + // System Calls V1.1 + WIN_REQUEST_REPAINT, + WIN_SET_LABEL_TEXT, + WIN_ADD_MENUBAR_ITEM, + WIN_SET_SCROLL_BAR_MIN, + WIN_SET_SCROLL_BAR_MAX, + WIN_SET_SCROLL_BAR_POS, + WIN_GET_SCROLL_BAR_POS, + WIN_ADD_ELEM_TO_LIST, + WIN_REM_ELEM_FROM_LIST, + WIN_GET_ELEM_STR_FROM_LIST, + WIN_CLEAR_LIST, + + CON_PUTSTRING, + CON_READCHAR, + CON_READSTR, + + MM_ALLOCATE_D, + MM_FREE, + MM_DEBUG_DUMP, + + FI_OPEN_D, + FI_CLOSE, + FI_READ, + FI_WRITE, + FI_TELL, + FI_TELLSIZE, + FI_SEEK, + + // System Calls V1.2 + WIN_SET_HUGE_LABEL_TEXT, + WIN_SET_INPUT_TEXT_TEXT, + WIN_SET_WINDOW_ICON, + WIN_SET_WINDOW_TITLE, + WIN_REGISTER_EVENT, + WIN_REGISTER_EVENT2, + + TM_GET_TICK_COUNT, + TM_GET_TIME, + + CPU_GET_TYPE, + CPU_GET_NAME, + + CON_GET_CURRENT_CONSOLE, + + //V1.21 + VID_BLIT_IMAGE_RESIZE, + TM_SLEEP, + + //V1.22 + WIN_SET_ICON, + + //V1.23 + NS_GET_VERSION, + + //V1.24 + WIN_GET_THEME_PARM, + WIN_SET_THEME_PARM, + + // System Calls V1.3 + WIN_ADD_CONTROL_EX, + WIN_TEXT_INPUT_QUERY_DIRTY_FLAG, + WIN_TEXT_INPUT_CLEAR_DIRTY_FLAG, + WIN_TEXT_INPUT_GET_RAW_TEXT, + WIN_CHECKBOX_GET_CHECKED, + WIN_CHECKBOX_SET_CHECKED, + + CC_RUN_C_CODE, + + FI_REMOVE_FILE, + + WIN_REQUEST_REPAINT_NEW, + WIN_SHELL_ABOUT, + WIN_INPUT_BOX, + WIN_COLOR_BOX, + WIN_FILE_CHOOSE_BOX,//TODO + WIN_POPUP_WINDOW, + + // System Calls V1.4 + VID_SET_VBE_DATA,//dangerous!! be careful!! + + FI_OPEN_DIR_D, + FI_CLOSE_DIR, + FI_READ_DIR_LEGACY, + FI_SEEK_DIR, + FI_REWIND_DIR, + FI_TELL_DIR, + FI_STAT_AT, + FI_STAT, + FI_GET_CWD, + FI_CHANGE_DIR, + + WIN_GET_WIDGET_EVENT_HANDLER, + WIN_SET_WIDGET_EVENT_HANDLER, + WIN_SET_IMAGE_CTL_MODE, + WIN_SET_IMAGE_CTL_COLOR, + WIN_SET_IMAGE_CTL_IMAGE, + WIN_GET_IMAGE_CTL_IMAGE, + WIN_IMAGE_CTL_ZOOM_TO_FILL, + WIN_SET_FOCUSED_CONTROL, + WIN_POPUP_WINDOW_EX, + + ERR_GET_STRING, + + VID_GET_MOUSE_POS, + VID_SET_CLIP_RECT, + + CB_CLEAR, + CB_COPY_TEXT, + CB_COPY_BLOB, + CB_GET_CURRENT_VARIANT,//danger!! + CB_RELEASE, + + // System Calls V1.5 + VID_RENDER_ICON, + VID_RENDER_ICON_OUTLINE, + VID_RENDER_ICON_SIZE, + VID_RENDER_ICON_SIZE_OUTLINE, + TM_GET_RANDOM, + + // System Calls V1.6 + MM_REALLOCATE_D, + SH_EXECUTE, + SH_EXECUTE_RESOURCE, + + // System Calls V1.7 + MM_MAP_MEMORY_USER, + MM_UNMAP_MEMORY_USER, + + // System Calls V1.8 + FI_RENAME, + FI_MAKE_DIR, + FI_REMOVE_DIR, + FI_CREATE_PIPE, + FI_IO_CONTROL, + WIN_CALL_CTL_CALLBACK, + WIN_TEXT_INPUT_SET_MODE, + + // System Calls V1.9 + WIN_GET_SCROLL_BAR_MIN, + WIN_GET_SCROLL_BAR_MAX, + WIN_GET_SEL_INDEX_LIST, + WIN_SET_SEL_INDEX_LIST, + WIN_GET_SEL_INDEX_TABLE, + WIN_SET_SEL_INDEX_TABLE, + WIN_GET_SCROLL_TABLE, + WIN_SET_SCROLL_TABLE, + WIN_ADD_TABLE_ROW, + WIN_ADD_TABLE_COLUMN, + WIN_GET_ROW_STRINGS_FROM_TABLE, + WIN_REMOVE_ROW_FROM_TABLE, + WIN_RESET_TABLE, + + // System Calls V2.0 + VID_READ_PIXEL, + CFG_GET_STRING, + VID_GET_VBE_DATA, + + // System Calls V2.1 + WIN_GET_WINDOW_TITLE, + WIN_GET_WINDOW_DATA, + WIN_SET_WINDOW_DATA, + WIN_GET_WINDOW_RECT, + WIN_CALL_CALLBACK_AND_CTLS, + WIN_CHANGE_CURSOR, + WIN_SET_FLAGS, + WIN_GET_FLAGS, + + // System Calls V2.2 + VID_SET_MOUSE_POS, + WIN_ADD_TIMER, + WIN_DISARM_TIMER, + WIN_CHANGE_TIMER, + + // System Calls V2.3 + WIN_UPLOAD_CURSOR, + WIN_RELEASE_CURSOR, + WIN_SET_LIST_ITEM_TEXT, + WIN_GET_ICON_IMAGE, + RST_LOOK_UP_RESOURCE, + WIN_SET_CONTROL_DISABLED, + WIN_SET_CONTROL_FOCUSED, + WIN_SET_CONTROL_VISIBLE, + WIN_PROG_BAR_SET_PROGRESS, + WIN_PROG_BAR_SET_MAX_PROG, + + // System Calls V2.4 + WIN_COMBO_BOX_ADD_ITEM, + WIN_COMBO_BOX_GET_SELECTED_ITEM, + WIN_COMBO_BOX_SET_SELECTED_ITEM, + WIN_COMBO_BOX_CLEAR_ITEMS, + WIN_IS_CONTROL_FOCUSED, + WIN_IS_CONTROL_DISABLED, + WIN_TEXT_INPUT_SET_FONT, + WIN_TEXT_INPUT_REQUEST_COMMAND, + + // System Calls V2.5 + WIN_DRAW_EDGE, + WIN_DRAW_ARROW, + WIN_TAB_VIEW_ADD_TAB, + WIN_TAB_VIEW_REMOVE_TAB, + WIN_TAB_VIEW_CLEAR_TABS, + WIN_SPAWN_MENU, + KB_GET_KEY_STATE, + LCK_ACQUIRE, + LCK_FREE, + + // System Calls V2.6 + FI_READ_DIR, + FI_STAT_LINK, +}; + +__attribute__((noreturn)) +void abort (); + +int memcmp (const void* ap, const void* bp, size_t size); +void* memcpy (void* dstptr, const void* srcptr, size_t size); +void* memmove (void* dstptr, const void* srcptr, size_t size); +void* memset (void* bufptr, int val, size_t size); +size_t strlen (const char* str); +char* strcpy (char *dst, const char* src); +char* strncpy (char *dst, const char *src, size_t n); +size_t strlcpy (char *dst, const char *src, size_t n); +int strcmp (const char* as, const char* bs); +int strncmp (const char* s1, const char* s2, size_t n); +char* strcat (char* dest, const char* after); +void strtolower (char* as); +void strtoupper (char* as); +void memtolower (char* as, int w); +void memtoupper (char* as, int w); +size_t strgetlento(const char* str, char chr); +char* strdup (const char *pText); +char* strstr (const char *string, const char *substring); +size_t strnlen (const char* str, size_t szmax); +char* strchr (const char* s, int c); +char* strrchr (const char* s, int c); +char* strchrnul (const char* s, int c); // GNU extension +char* Tokenize (TokenState* pState, char* pString, char* separator); + +void* malloc (size_t size); +void* calloc (size_t nmemb, size_t size); +void free (void* ptr); + +void exit (int num); + +void LogMsg ( const char *pfmt, ... ); +void LogMsgNoCr ( const char *pfmt, ... ); + +int SetErrorNumber(int errno); +int GetErrorNumber(); +int* GetErrorNumberPointer(); + +int sprintf(char* buf, const char* fmt, ...); + +void OnAssertionFail(const char *cond_msg, const char *file, int line); +#define assert(cond) do { if (!(cond)) OnAssertionFail(#cond, __FILE__, __LINE__); } while (0) +#define ASSERT assert + +#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg) + +#endif//_CRTLIB_H \ No newline at end of file diff --git a/crt2/src/entry.c b/crt2/src/entry.c new file mode 100644 index 00000000..f09fa960 --- /dev/null +++ b/crt2/src/entry.c @@ -0,0 +1,62 @@ +// *************************************************************** +// entry.c - Creation date: 21/04/2022 +// ------------------------------------------------------------- +// NanoShell C Runtime Library +// Copyright (C) 2022 iProgramInCpp - Licensed under GPL V3 +// +// *************************************************************** +// Programmer(s): iProgramInCpp (iprogramincpp@gmail.com) +// *************************************************************** + +#include "crtlib.h" +#include "crtinternal.h" + +__attribute__((noreturn)) void exit (int number); + +int main(int argc, char** argv); +void MemMgrInitializeMemory(); + +void _I_Setup(); + +__attribute__((noreturn)) +void _CEntry(const char* arg) +{ + MemMgrInitializeMemory(); + + _I_Setup(); + + char* argv[128]; + argv[0] = NULL; + + int returnValue; + + // No arguments? Just call with argc of 0 + if (*arg == 0) + { + returnValue = main(0, argv); + exit (returnValue); + } + + // Have arguments. Copy argument string + int slen = strlen (arg); + char string [slen + 1]; + strcpy (string, arg); + + // Tokenize passed in argument string. + int argc = 0; + + TokenState pState; + memset (&pState, 0, sizeof pState); + + argv[argc++] = Tokenize (&pState, string, " "); + while ((argv[argc++] = Tokenize (&pState, NULL, " "))); + if (argv[argc - 1] == NULL) + argc--; + + // Finally call the real entry point + returnValue = main(argc, argv); + exit(returnValue); + + // no return. +} + diff --git a/crt2/src/math.asm b/crt2/src/math.asm new file mode 100644 index 00000000..100e41c8 --- /dev/null +++ b/crt2/src/math.asm @@ -0,0 +1 @@ +; Everything in this file is now linked from libgcc. \ No newline at end of file diff --git a/crt2/src/zstub.c b/crt2/src/zstub.c new file mode 100644 index 00000000..22503483 --- /dev/null +++ b/crt2/src/zstub.c @@ -0,0 +1,2 @@ +// This is a stub. +// crti.o and crtn.o are both unused, crt1.o is the one that actually contains runtime code. \ No newline at end of file diff --git a/fs/Bin/List.nse b/fs/Bin/List.nse index 879d6a4a..ab0bcf85 100644 Binary files a/fs/Bin/List.nse and b/fs/Bin/List.nse differ diff --git a/fs/libnanoshell.so b/fs/libnanoshell.so new file mode 100644 index 00000000..ed56b479 Binary files /dev/null and b/fs/libnanoshell.so differ diff --git a/include/elf.h b/include/elf.h index 730e50a7..2cbbada5 100644 --- a/include/elf.h +++ b/include/elf.h @@ -11,6 +11,8 @@ #include #include +#define C_MAX_ELF_LIBRARIES (32) + #define SAFE_FREE(ptr) do { \ if (ptr) { \ MmFree(ptr); \ @@ -112,6 +114,8 @@ enum { ELF_TYPE_NONE = 0, //Unknown ELF_TYPE_RELOC, //Relocatable file ELF_TYPE_EXEC, //Executable file + ELF_TYPE_DYN, //Shared object + ELF_TYPE_CORE, //Core dump file }; #define ELF_MACH_386 3 //x86 Machine type @@ -136,6 +140,10 @@ enum { ELF_EXEC_BLOCKED, ELF_EXEC_BLOCKED_GLOBALLY, ELF_RESOURCE_TABLE_NOT_ORDERED, + ELF_LIB_TOO_MANY_LIBRARIES, + ELF_LIB_INVALID_PROGHDRS, + ELF_LIB_BAD_RELOC_ENTRY, + ELF_LIB_OUT_OF_MEMORY, ELF_ERR_COUNT, }; @@ -156,6 +164,52 @@ enum //... }; +typedef struct +{ + UserHeap* m_heap; +} +ElfProcess; + +typedef struct +{ + // If the shared library is used. + bool m_bUsed; + + // The pointer to the shared object. To unload it, simply MmFree() it. + void* m_pPtr; + + // Amount of users of the object. If it's 0, it can be unloaded at any time. + // A user is an object file that hooked into the library. + int m_nUsers; + + // The symbol table of the shared object. + void* m_pSymTab; + + // The string table of the shared object. + void* m_pStrTab; +} +ElfSharedObject; + +typedef struct +{ + void* pFileData; + size_t nFileSize; + bool bGui; //false if ran from command shell + bool bAsync; //false if the parent is waiting for this to finish + bool bExecDone; //true if the execution of this process has completed + int nHeapSize; //can be dictated by user settings later, for now it should be 512 + char sArgs[1024]; + char sFileName[PATH_MAX+5]; + int nElfErrorCode; // The error code that the ELF executive returns if the ELF file didn't run + int nElfErrorCodeExec; // The error code that the ELF file itself returns. + void* pSymTab; + void* pStrTab; + bool bSetUpSymTab; + int nSymTabEntries; + uint64_t nParentTaskRID; +} +ElfLoaderBlock; + const char *ElfGetErrorMsg (int error_code); int ElfRunProgram(const char *pFileName, const char *args, bool bAsync, bool bGui, UNUSED int nHeapSize, int *pElfErrorCodeOut); ElfSymbol* ExLookUpSymbol(Process* pProc, uintptr_t address); diff --git a/src/elf.c b/src/elf.c index 890873f3..72af4d75 100644 --- a/src/elf.c +++ b/src/elf.c @@ -8,12 +8,13 @@ #include #include #include +#include #include #include #include #include "mm/memoryi.h" // The ELF loader has legitimate reason to use memory manager's internal stuff. -//#define ELF_DEBUG +#define ELF_DEBUG //#define ELFSYM_DEBUG #ifdef ELF_DEBUG @@ -22,11 +23,58 @@ #define EDLogMsg(...) #endif -typedef struct +SafeLock g_ElfSharedObjectLock; +ElfSharedObject g_ElfSharedObjects[C_MAX_ELF_LIBRARIES]; + +ElfSharedObject* ElfCreateEmptySharedObject() { - UserHeap* m_heap; + LockAcquire(&g_ElfSharedObjectLock); + + ElfSharedObject* pObj = NULL; + for (int i = 0; i < C_MAX_ELF_LIBRARIES; i++) + { + if (!g_ElfSharedObjects[i].m_bUsed) + { + pObj = &g_ElfSharedObjects[i]; + pObj->m_bUsed = true; + break; + } + } + + LockFree(&g_ElfSharedObjectLock); + return pObj; +} + +bool ElfTryFreeSharedObject(ElfSharedObject* pSO) +{ + bool bInterruptsWereCleared = false; + if (!KeCheckInterruptsDisabled()) + { + bInterruptsWereCleared = true; + // clear interrupts to ensure that no more users are coming: + cli; + } + + // If there are still people using this library, bail + if (pSO->m_nUsers) + goto EndFailure; + + pSO->m_bUsed = false; + + // We keep the interrupts cleared to free these: + MmFreeID(pSO->m_pPtr); + MmFreeID(pSO->m_pSymTab); + MmFreeID(pSO->m_pStrTab); + + if (bInterruptsWereCleared) + sti; + return true; + +EndFailure: + if (bInterruptsWereCleared) + sti; + return false; } -ElfProcess; const char* ElfGetArchitectureString(uint16_t machine, uint8_t word_size) { @@ -96,16 +144,20 @@ void ElfCleanup (UNUSED ElfProcess* pProcess) { } -void ElfMapAddress(ElfProcess* pProc, void *virt, size_t size, void* data, size_t fileSize) +bool ElfMapAddress(ElfProcess* pProc, void *virt, size_t size, void* data, size_t fileSize) { uintptr_t virtHint = (uintptr_t)virt & ~(PAGE_SIZE - 1), virtOffset = (uintptr_t)virt & (PAGE_SIZE - 1); size_t sizePages = (((size + virtOffset - 1) >> 12) + 1); - MuMapMemoryFixedHint(pProc->m_heap, virtHint, sizePages, NULL, true, CLOBBER_SKIP, false, PAGE_BIT_SCRUB_ZERO); + if (!MuMapMemoryFixedHint(pProc->m_heap, virtHint, sizePages, NULL, true, CLOBBER_SKIP, false, PAGE_BIT_SCRUB_ZERO)) + { + return false; + } //memset((void*)virtHint, 0, sizePages * PAGE_SIZE); memcpy(virt, data, fileSize); + return true; } void ElfDumpInfo(ElfHeader* pHeader) @@ -117,26 +169,6 @@ void ElfDumpInfo(ElfHeader* pHeader) extern int g_lastReturnCode; -typedef struct -{ - void* pFileData; - size_t nFileSize; - bool bGui; //false if ran from command shell - bool bAsync; //false if the parent is waiting for this to finish - bool bExecDone; //true if the execution of this process has completed - int nHeapSize; //can be dictated by user settings later, for now it should be 512 - char sArgs[1024]; - char sFileName[PATH_MAX+5]; - int nElfErrorCode; // The error code that the ELF executive returns if the ELF file didn't run - int nElfErrorCodeExec; // The error code that the ELF file itself returns. - void* pSymTab; - void* pStrTab; - bool bSetUpSymTab; - int nSymTabEntries; - uint64_t nParentTaskRID; -} -ElfLoaderBlock; - // TODO: Maybe update this to outside of the elf bubble? It could work for other executable files too ElfSymbol* ElfGetSymbolAtIndex(ElfLoaderBlock* pLBlock, int index) @@ -300,31 +332,17 @@ void ElfSetupSymTabEntries(ElfSymbol** pSymbolsPtr, const char* pStrTab, int* pn *pSymbolsPtr = pNewSymbols; } -static int ElfExecute (void *pElfFile, UNUSED size_t size, const char* pArgs, int *pErrCodeOut, ElfLoaderBlock* pLoaderBlock) +// Hint is for relocatables +static int ElfLoadProgram(ElfProcess* pProcess, ElfHeader* pHeader, ElfLoaderBlock* pLoaderBlock) { - EDLogMsg("Loading elf file"); - - // The heap associated with this process - UserHeap *pHeap = MuGetCurrentHeap(); - - ElfProcess proc; - memset(&proc, 0, sizeof(proc)); - - proc.m_heap = pHeap; - + void* pElfFile = pHeader; uint8_t* pElfData = (uint8_t*)pElfFile; //to do arithmetic with this - //check the header. - ElfHeader* pHeader = (ElfHeader*)pElfFile; - - int errCode = ElfIsSupported(pHeader); - if (errCode != 1) //not supported. - { - LogMsg("Got error %d while loading the elf.", errCode); - return errCode; - } bool failed = false; + uint32_t relocationOffset = 0, maxSize = 0; + // Navigate the program headers. If one + EDLogMsg("(loading prog hdrs into memory...)"); for (int i = 0; i < pHeader->m_phNum; i++) { @@ -349,139 +367,169 @@ static int ElfExecute (void *pElfFile, UNUSED size_t size, const char* pArgs, in } else { - ElfMapAddress (&proc, addr, size1, &pElfData[offs], size2); + if (!ElfMapAddress(pProcess, addr, size1, &pElfData[offs], size2)) + { + failed = true; + break; + } } } if (failed) return ELF_INVALID_SEGMENTS; + + EDLogMsg("(loaded and mapped everything, activating heap!)"); + + int strTabShLink = -1, symTabIndex = -1; + + for (int i = 0; i < pHeader->m_shNum; i++) { - EDLogMsg("(loaded and mapped everything, activating heap!)"); - MuUseHeap (pHeap); + ElfSectHeader* pSectHeader = (ElfSectHeader*)(pElfData + pHeader->m_shOffs + i * pHeader->m_shEntSize); - int strTabShLink = -1, symTabIndex = -1; - - for (int i = 0; i < pHeader->m_shNum; i++) + if (pSectHeader->m_type == SHT_SYMTAB) + { + strTabShLink = pSectHeader->m_shLink; + symTabIndex = i; + break; + } + } + + ElfSectHeader* pShStrTabHdr = (ElfSectHeader*)(pElfData + pHeader->m_shOffs + pHeader->m_shStrNdx * pHeader->m_shEntSize); + + for (int i = 0; i < pHeader->m_shNum; i++) + { + ElfSectHeader* pSectHeader = (ElfSectHeader*)(pElfData + pHeader->m_shOffs + i * pHeader->m_shEntSize); + if (pSectHeader->m_type == SHT_NOBITS) { - ElfSectHeader* pSectHeader = (ElfSectHeader*)(pElfData + pHeader->m_shOffs + i * pHeader->m_shEntSize); - if (pSectHeader->m_type == SHT_SYMTAB) - { - strTabShLink = pSectHeader->m_shLink; - symTabIndex = i; - break; - } } - - ElfSectHeader* pShStrTabHdr = (ElfSectHeader*)(pElfData + pHeader->m_shOffs + pHeader->m_shStrNdx * pHeader->m_shEntSize); - - for (int i = 0; i < pHeader->m_shNum; i++) + if (pSectHeader->m_type == SHT_PROGBITS) { - ElfSectHeader* pSectHeader = (ElfSectHeader*)(pElfData + pHeader->m_shOffs + i * pHeader->m_shEntSize); - if (pSectHeader->m_type == SHT_NOBITS) - { - - } - if (pSectHeader->m_type == SHT_PROGBITS) - { - // check the header's name - const char* pName = (const char*)(pElfData + pShStrTabHdr->m_offset + pSectHeader->m_name); - - if (strcmp(pName, ".nanoshell") == 0) - ExSetProgramInfo((ProgramInfo*)pSectHeader->m_addr); - else if (strcmp(pName, ".nanoshell_resources") == 0) - if (!ExLoadResourceTable((void*)pSectHeader->m_addr)) - { - failed = true; - break; - } - } - if (pSectHeader->m_type == SHT_SYMTAB) + // check the header's name + const char* pName = (const char*)(pElfData + pShStrTabHdr->m_offset + pSectHeader->m_name); + + if (strcmp(pName, ".nanoshell") == 0) { - SLogMsg("Found SymTab. m_offset: %x Size: %x", pSectHeader->m_offset, pSectHeader->m_shSize); - - uint8_t* pTableStart = &pElfData[pSectHeader->m_offset]; - size_t nTableSize = pSectHeader->m_shSize; - - // allocate the symbol table - void *pTableMem = MmAllocate(nTableSize); - - // copy the contents from the ELF data - memcpy(pTableMem, pTableStart, nTableSize); - - // set the loader block's relevant fields - pLoaderBlock->pSymTab = pTableMem; - pLoaderBlock->nSymTabEntries = nTableSize / sizeof(ElfSymbol); - - // have we loaded the strtab? - if (pLoaderBlock->pStrTab && !pLoaderBlock->bSetUpSymTab) - { - ElfSetupSymTabEntries((ElfSymbol**)&pLoaderBlock->pSymTab, (const char*)pLoaderBlock->pStrTab, &pLoaderBlock->nSymTabEntries); - pLoaderBlock->bSetUpSymTab = true; - } + ExSetProgramInfo((ProgramInfo*)pSectHeader->m_addr); } - if (pSectHeader->m_type == SHT_STRTAB && i == strTabShLink) + else if (strcmp(pName, ".nanoshell_resources") == 0) { - SLogMsg("Found StrTab. m_offset: %x Size: %x", pSectHeader->m_offset, pSectHeader->m_shSize); - - uint8_t* pTableStart = &pElfData[pSectHeader->m_offset]; - size_t nTableSize = pSectHeader->m_shSize; - - // allocate the symbol table - void *pTableMem = MmAllocate(nTableSize); - - // copy the contents from the ELF data - memcpy(pTableMem, pTableStart, nTableSize); - - // set the loader block's relevant fields - pLoaderBlock->pStrTab = pTableMem; - - // have we loaded the symtab? - if (pLoaderBlock->pSymTab && !pLoaderBlock->bSetUpSymTab) + if (!ExLoadResourceTable((void*)pSectHeader->m_addr)) { - ElfSetupSymTabEntries((ElfSymbol**)&pLoaderBlock->pSymTab, (const char*)pLoaderBlock->pStrTab, &pLoaderBlock->nSymTabEntries); - pLoaderBlock->bSetUpSymTab = true; + failed = true; + break; } } } - - // now, copy the symtab and strtab data into the process' structure - Process* pThisProcess = ExGetRunningProc(); - pThisProcess->pSymTab = pLoaderBlock->pSymTab; - pThisProcess->pStrTab = pLoaderBlock->pStrTab; - pThisProcess->nSymTabEntries = pLoaderBlock->nSymTabEntries; - - EDLogMsg("The ELF setup is done, jumping to the entry! Wish us luck!!!"); - - // test out the resource stuff - Resource* pResource = ExLookUpResource(10000); - - if (!pResource) + if (pSectHeader->m_type == SHT_SYMTAB) { - SLogMsg("Resource 10000 not found."); + SLogMsg("Found SymTab. m_offset: %x Size: %x", pSectHeader->m_offset, pSectHeader->m_shSize); + + uint8_t* pTableStart = &pElfData[pSectHeader->m_offset]; + size_t nTableSize = pSectHeader->m_shSize; + + // allocate the symbol table + void *pTableMem = MmAllocate(nTableSize); + + // copy the contents from the ELF data + memcpy(pTableMem, pTableStart, nTableSize); + + // set the loader block's relevant fields + pLoaderBlock->pSymTab = pTableMem; + pLoaderBlock->nSymTabEntries = nTableSize / sizeof(ElfSymbol); + + // have we loaded the strtab? + if (pLoaderBlock->pStrTab && !pLoaderBlock->bSetUpSymTab) + { + ElfSetupSymTabEntries((ElfSymbol**)&pLoaderBlock->pSymTab, (const char*)pLoaderBlock->pStrTab, &pLoaderBlock->nSymTabEntries); + pLoaderBlock->bSetUpSymTab = true; + } } - else + if (pSectHeader->m_type == SHT_STRTAB && i == strTabShLink) { - SLogMsg("Resource 10000 Found Type %d", pResource->m_type); + SLogMsg("Found StrTab. m_offset: %x Size: %x", pSectHeader->m_offset, pSectHeader->m_shSize); + + uint8_t* pTableStart = &pElfData[pSectHeader->m_offset]; + size_t nTableSize = pSectHeader->m_shSize; + + // allocate the symbol table + void *pTableMem = MmAllocate(nTableSize); + + // copy the contents from the ELF data + memcpy(pTableMem, pTableStart, nTableSize); + + // set the loader block's relevant fields + pLoaderBlock->pStrTab = pTableMem; + + // have we loaded the symtab? + if (pLoaderBlock->pSymTab && !pLoaderBlock->bSetUpSymTab) + { + ElfSetupSymTabEntries((ElfSymbol**)&pLoaderBlock->pSymTab, (const char*)pLoaderBlock->pStrTab, &pLoaderBlock->nSymTabEntries); + pLoaderBlock->bSetUpSymTab = true; + } } - - //now that we have switched, call the entry func: - ElfEntry entry = (ElfEntry)pHeader->m_entry; - - // this is a bit complex, but I'll break it down. This does a couple things: - // - push `pArgs` as the only argument (%1) - // - call `entry` (%2) - // - restore esp to normal - // - mark ebx, esi, and edi as being clobbered - // - the return value is in %0 (eax) - int returnValue = 0; - asm("pushl %1\ncall *%2\nadd $4, %%esp" : "=a"(returnValue) : "r"(pArgs), "r"(entry) : "ebx", "esi", "edi"); - - EDLogMsg("Executable has exited."); - - *pErrCodeOut = g_lastReturnCode = returnValue; } - return failed ? ELF_INVALID_SEGMENTS : ELF_ERROR_NONE; + if (failed) + { + MmFree(pLoaderBlock->pSymTab); + MmFree(pLoaderBlock->pStrTab); + return ELF_INVALID_SEGMENTS; + } + + return ELF_ERROR_NONE; +} + +static int ElfExecute (void *pElfFile, UNUSED size_t size, const char* pArgs, int *pErrCodeOut, ElfLoaderBlock* pLoaderBlock) +{ + EDLogMsg("Loading elf file"); + + // The heap associated with this process + UserHeap *pHeap = MuGetCurrentHeap(); + + ElfProcess proc; + memset(&proc, 0, sizeof(proc)); + + proc.m_heap = pHeap; + + uint8_t* pElfData = (uint8_t*)pElfFile; //to do arithmetic with this + //check the header. + ElfHeader* pHeader = (ElfHeader*)pElfFile; + + int errCode = ElfIsSupported(pHeader); + if (errCode != 1) //not supported. + { + LogMsg("Got error %d while loading the elf.", errCode); + return errCode; + } + + // load the program into memory: + int result = ElfLoadProgram(&proc, pHeader, pLoaderBlock); + if (result != ELF_ERROR_NONE) + return result; + + // now, copy the symtab and strtab data into the process' structure + Process* pThisProcess = ExGetRunningProc(); + pThisProcess->pSymTab = pLoaderBlock->pSymTab; + pThisProcess->pStrTab = pLoaderBlock->pStrTab; + pThisProcess->nSymTabEntries = pLoaderBlock->nSymTabEntries; + + //now that we have switched, call the entry func: + ElfEntry entry = (ElfEntry)pHeader->m_entry; + + // this is a bit complex, but I'll break it down. This does a couple things: + // - push `pArgs` as the only argument (%1) + // - call `entry` (%2) + // - restore esp to normal + // - mark ebx, esi, and edi as being clobbered + // - the return value is in %0 (eax) + int returnValue = 0; + asm("pushl %1\ncall *%2\nadd $4, %%esp" : "=a"(returnValue) : "r"(pArgs), "r"(entry) : "ebx", "esi", "edi"); + + EDLogMsg("Executable has exited."); + + *pErrCodeOut = g_lastReturnCode = returnValue; + + return ELF_ERROR_NONE; } const char *gElfErrorCodes[] = @@ -503,6 +551,11 @@ const char *gElfErrorCodes[] = "The execution of this program was terminated.", "The execution of this file is not permitted at the moment.", "The execution of program files is not permitted. Please contact your system administrator.", + "The resource table of the image file %s is not ordered." + "The shared library %s could not be loaded because there are too many libraries loaded.", + "The shared library %s could not be loaded because of an invalid program segment layout.", + "The shared library %s could not be loaded because of a corrupted relocation entry.", + "The shared library %s could not be loaded because the system has run out of memory.", }; const char *ElfGetErrorMsg (int error_code)