diff --git a/programs/bcc32/examples/hello.cpp b/programs/bcc32/examples/hello.cpp new file mode 100644 index 0000000000..b8ad7652db --- /dev/null +++ b/programs/bcc32/examples/hello.cpp @@ -0,0 +1,34 @@ +#include "../include/kolibri.h" +#include "../include/kos_heap.h" +#include "../include/kos_file.h" + +using namespace Kolibri; + +const char header[] = "Hello World test"; +const char string[] = "Hello, World!"; + +bool KolibriOnStart(TStartData &me_start, TThreadData /*th*/) +{ + me_start.Left = 10; + me_start.Top = 40; + me_start.Width = 150; + me_start.Height = 80; + me_start.WinData.Title = header; + return true; +} + +void KolibriOnPaint(void) +{ + DrawText(30,10,0,string); +} + +bool KolibriOnClose(TThreadData /*th*/) +{return true;} +int KolibriOnIdle(TThreadData /*th*/) +{return -1;} +void KolibriOnSize(int /*window_rect*/[], TThreadData /*th*/) +{} +void KolibriOnKeyPress(TThreadData /*th*/) +{GetKey();} +void KolibriOnMouse(TThreadData /*th*/) +{} \ No newline at end of file diff --git a/programs/bcc32/examples/hello_cpp.bat b/programs/bcc32/examples/hello_cpp.bat new file mode 100644 index 0000000000..c3128d40ed --- /dev/null +++ b/programs/bcc32/examples/hello_cpp.bat @@ -0,0 +1,6 @@ +kos32-bcc -S -v- -R- -6 -a4 -O2 -Og -Oi -Ov -OS -k- -D__KOLIBRI__ -Iinclude hello.cpp +echo include "kos_make.inc" > f_hello.asm +t2fasm < hello.asm >> f_hello.asm +fasm f_hello.asm hello.kex +kpack hello.kex +pause \ No newline at end of file diff --git a/programs/bcc32/examples/kos_make.inc b/programs/bcc32/examples/kos_make.inc new file mode 100644 index 0000000000..ed01d52d00 --- /dev/null +++ b/programs/bcc32/examples/kos_make.inc @@ -0,0 +1,7 @@ +STACKSIZE equ 102400 +HEAPSIZE equ 102400 + +include "..\..\proc32.inc" +include "..\include\kos_start.inc" +include "..\include\kos_func.inc" +include "..\include\kos_heap.inc" diff --git a/programs/bcc32/include/kolibri.h b/programs/bcc32/include/kolibri.h new file mode 100644 index 0000000000..d5ca3ae389 --- /dev/null +++ b/programs/bcc32/include/kolibri.h @@ -0,0 +1,538 @@ +#ifndef __KOLIBRI_H_INCLUDED_ +#define __KOLIBRI_H_INCLUDED_ + +#include "kos_lib.h" + +// Kolibri interface. + +namespace Kolibri // All kolibri functions, types and data are nested in the (Kolibri) namespace. +{ + const char *DebugPrefix = "User program: "; + char CommandLine[257]; + + struct TWindowData // Data for drawing a window. + { + unsigned short WindowType, HeaderType; + unsigned long WindowColor, HeaderColor, BorderColor, TitleColor; + const char *Title; + }; + + struct TStartData // This structure is used only for KolibriOnStart function. + { + unsigned short Left, Width, Top, Height; // Initial window rectangle. + TWindowData WinData; + }; + + typedef void **TThreadData; // Thread data are the fast identifier of thread, contains user dword in + //_ the zero element and stack beginning (or zero if it is unknown) in the first element. + //_ The stack will be deleted from dynamic memory at the finish of the thread if stack beginning is not zero. + + struct TMutex; // Simple mutex can be locked only once at a time. +#define KOLIBRI_MUTEX_INIT {} // Simple mutex initializer, cat be redefined in a realization of the library + + struct TRecMutex; // Recursive mutex can be locked many times by a single thread at a time. +#define KOLIBRI_REC_MUTEX_INIT {} // Recursive mutex initializer, cat be redefined in a realization of the library + + // Some functions have two forms: the fast form with (thread_data) parameter and the form without it. + // Note: pass only thread data of current thread as (thread_data) parameter to these functions. + + void Main(); // Main function is called at program startup. + void* ThreadMain(void *user = 0, void *stack_begin = 0); + // Called at thread startup, (user) is placed in thread data as a user dword, + //_ (stack_begin) is placed in thread data as a stack beginning. + //_ Return new value of stack beginning that can be changed in the thread data. + void GetWindowData(TWindowData &win_data); // Write current window data to (win_data). + void GetWindowData(TWindowData &win_data, TThreadData thread_data); + void SetWindowData(const TWindowData &win_data); // Replace current window data by (win_data). + void SetWindowData(const TWindowData &win_data, TThreadData thread_data); + void CloseWindow(); // Close current window when returning to message loop. + void CloseWindow(TThreadData thread_data); + void Redraw(int frame = 0); // Redraw current window immediately, if (frame) is positive redraw the frame too, + void Redraw(int frame, TThreadData thread_data); //_ if (frame) is negative redraw only invalideted window. + void Invalidate(int frame = 0); // Redraw current window when no message will be is the queue, + void Invalidate(int frame, TThreadData thread_data); //_ if (frame) is positive redraw the frame too, + //_ if (frame) is negative do nothing. + void MoveWindow(const int window_rect[/* 4 */]); // Move and resize current window. + + void Abort(); // Abnormally terminate a program. + void ExitProcess(); // Exit from the process, don't call any destructors of global varyables + void ExitThread(); // Exit from the current thread + void ExitThread(TThreadData thread_data); + void ReturnMessageLoop(); // Return to the message loop of the thread. Exit from the thread + void ReturnMessageLoop(TThreadData thread_data); //_ if it is called from (KolibriOnStart). + + void Delay(unsigned int time); // Delay the execution of the program during (time) hundredth seconds. + unsigned int Clock(); // Return the time from starting of the system to this moment in hundredth of seconds. + int GetPackedTime(); // Return the current time of day in binary-decimal format 0x00SSMMHH. + void GetTime(int t[/* 3 */]); // Write the current time to (t): t[0] = second, t[1] = minute, t[2] = hour. + int GetPackedDate(); // Return the current date in binary-decimal format 0x00YYDDMM. + void GetDate(int d[/* 3 */]); // Write the current date to (d): d[0] = day, d[1] = month, d[2] = year. + void GetTimeDate(int t[/* 6 */]); // Write the current time and date to (t): t[0] = second, + //_ t[1] = minute, t[2] = hour, t[3] = day, t[4] = month, t[5] = year. + void ReadCommonColors(unsigned int colors[/* 10 */]); // Writes standart window colors to (colors). + unsigned int GetProcessInfo(unsigned int *use_cpu, char process_name[/* 13 */], unsigned int *use_memory, + unsigned int *pid, int window_rect[/* 4 */], unsigned int pid_for = -1); + // Write (pid_for) process information to variables parameters points, return + //_ the number of processes. (pid_for) equal to (-1) means current process. + unsigned int GetPid(); // Return the current thread identifier (pid). + unsigned int GetPid(TThreadData thread_data); + TThreadData GetThreadData(); // Return the thread data of the current thread. + TThreadData GetThreadData(unsigned int pid); // Return the thread data of the thread with the given pid. + + void* GetPicture(unsigned short &width, unsigned short &height); + void* GetPicture(unsigned short &width, unsigned short &height, TThreadData thread_data); + // Return the picture on the window and write its width and height to (width) and (height). + void SetPicture(void *picture, unsigned short width, unsigned short height); + void SetPicture(void *picture, unsigned short width, unsigned short height, TThreadData thread_data); + // Replace the picture on the window by the given picture with the given width and height. + void GetBorderHeader(unsigned short &border_size, unsigned short &header_size); + void GetBorderHeader(unsigned short &border_size, unsigned short &header_size, TThreadData thread_data); + // Write the border thickness to (border_size) and header height to (header_size). + void GetClientSize(unsigned short &width, unsigned short &height); + void GetClientSize(unsigned short &width, unsigned short &height, TThreadData thread_data); + // Write the client area width and height to (width) and (height) parameters. + void GetClientSize(unsigned short &width, unsigned short &height, int win_width, int win_height); + void GetClientSize(unsigned short &width, unsigned short &height, int win_width, int win_height, TThreadData thread_data); + // Write the client area size of window with the width (win_width) + //_ and height (win_height) to (width) and (height) parameters. + void GetScreenSize(unsigned short &width, unsigned short &height); + // Write the screen width and height to (width) and (height) parameters. + + void InitMutex(TMutex *mutex); // Initialize the simple mutex. + void InitRecMutex(TRecMutex *mutex); // Initialize the recursive mutex. + bool TryLock(TMutex *mutex); // Try to lock the mutex without waitting, return true if lock. + bool TryLock(TRecMutex *mutex); + bool TryLock(TRecMutex *mutex, TThreadData thread_data); + bool TryLock(TRecMutex *mutex, unsigned int pid); + void Lock(TMutex *mutex); // Lock mutex and wait for it if this necessary. + void Lock(TRecMutex *mutex); + void Lock(TRecMutex *mutex, TThreadData thread_data); + void Lock(TRecMutex *mutex, unsigned int pid); + bool LockTime(TMutex *mutex, int time); + bool LockTime(TRecMutex *mutex, int time); // Lock mutex and wait for it during (time) hundredth seconds. + bool LockTime(TRecMutex *mutex, int time, TThreadData thread_data); + bool LockTime(TRecMutex *mutex, int time, unsigned int pid); + void UnLock(TMutex *mutex); // Unlock mutex + void UnLock(TRecMutex *mutex); + void UnLock(TRecMutex *mutex, TThreadData thread_data); + void UnLock(TRecMutex *mutex, unsigned int pid); + + void DebugPutChar(char c); // Put the character to the debug board. + void DebugPutString(const char *s); // Put the string to the debug board. + int GetKey(); // Return key pressed by user or -1 if no key was pressed. + int GetMouseButton(); // Return buttons pressed: 0 - no buttons, 1 - left button, 2 - right button, 3 - both buttons. + void GetMousePosition(short &x, short &y, bool absolute = false); + // Write mouse position to (x) and (y): absolute if (absolute) is true and relative the window otherwise. + void GetMousePosPicture(short &x, short &y); + + int GetThreadNumber(); // Return the number of threads currently executing. + bool WasThreadCreated(); // Return true if there was created at least one thread except the main thred. + unsigned int CreateThread(void *user = 0, unsigned int stack_size = 0, void *stack_end = 0); + // Create a new thread with the user dword (user) and stack pointer (stack_end). + //_ If (stack_end) is zero, create stack in dynamic memory of size (stack_size) or + //_ the same size as the main thread if (stack_size) less that 4096. Set the beginning + //_ of the stack if (stack_end) is zero or (stack_size) is not zero, in this case stack + //_ will be deleted automaticaly from dynamic memory at the finish of the thread. + void DrawText(short x, short y, int color, const char* string); +} + +// Function, defined outside. + +bool KolibriOnStart(Kolibri::TStartData &me_start, Kolibri::TThreadData thread_data); + // Window will be created iff return value is true. +bool KolibriOnClose(Kolibri::TThreadData thread_data); // Window will be closed iff return value is true. +int KolibriOnIdle(Kolibri::TThreadData thread_data); // Return the time to wait next message. +void KolibriOnSize(int window_rect[/* 4 */], Kolibri::TThreadData thread_data); // When the window is resized. +void KolibriOnKeyPress(Kolibri::TThreadData thread_data); // When user press a key. +void KolibriOnMouse(Kolibri::TThreadData thread_data); // When user move a mouse. + +#ifdef __KOLIBRI__ + +namespace Kolibri +{ +// Structures. + + struct TMutex // Simple mutex can be locked only once at a time. + { + unsigned int mut; + }; +#undef KOLIBRI_MUTEX_INIT +#define KOLIBRI_MUTEX_INIT {0x40} // Simple mutex initializer, cat be redefined in a realization of the library + + struct TRecMutex // Recursive mutex can be locked many times by a single thread at a time. + { + unsigned int mut, pid; + }; +#undef KOLIBRI_REC_MUTEX_INIT +#define KOLIBRI_REC_MUTEX_INIT {0x20,-1} // Recursive mutex initializer, cat be redefined in a realization of the library + +// Global variables. + + volatile TThreadData _ThreadTable[256]; + volatile unsigned int _ThreadScanCount[2] = {0, 0}; + volatile int _ThreadNumber = 1; + volatile int _ExitProcessNow = 0; + TMutex _ThreadMutex = KOLIBRI_MUTEX_INIT; + unsigned int _ThreadSavedBegProc[4]; + +// Inline functions. + + inline void GetWindowData(TWindowData &win_data) {GetWindowData(win_data, GetThreadData());} + + inline void SetWindowData(const TWindowData &win_data) {SetWindowData(win_data, GetThreadData());} + + inline void CloseWindow() {CloseWindow(GetThreadData());} + + inline void Redraw(int frame) {Redraw(frame, GetThreadData());} + + inline void Invalidate(int frame) {Invalidate(frame, GetThreadData());} + + inline void* GetPicture(unsigned short &width, unsigned short &height) + { + return GetPicture(width, height, GetThreadData()); + } + + inline void SetPicture(void *picture, unsigned short width, unsigned short height) + { + SetPicture(picture, width, height, GetThreadData()); + } + + inline void GetBorderHeader(unsigned short &border_size, unsigned short &header_size) + { + GetBorderHeader(border_size, header_size, GetThreadData()); + } + + inline void GetClientSize(unsigned short &width, unsigned short &height) + { + unsigned int pid; + int rect[4]; + GetProcessInfo(0, 0, 0, &pid, rect); + GetClientSize(width, height, rect[2], rect[3], GetThreadData(pid)); + } + + inline void GetClientSize(unsigned short &width, unsigned short &height, TThreadData thread_data) + { + int rect[4]; + GetProcessInfo(0, 0, 0, 0, rect); + GetClientSize(width, height, rect[2], rect[3], thread_data); + } + + inline void GetClientSize(unsigned short &width, unsigned short &height, int win_width, int win_height) + { + GetClientSize(width, height, win_width, win_height, GetThreadData()); + } + + inline void GetTimeDate(int t[/* 6 */]) {GetTime(t); GetDate(t + 3);} + + inline void InitMutex(TMutex *mutex) {mutex->mut = 0;} + + inline void InitRecMutex(TRecMutex *mutex) {mutex->mut = 0; mutex->pid = -1;} + + inline bool TryLock(TRecMutex *mutex) {return TryLock(mutex, GetPid());} + + inline bool TryLock(TRecMutex *mutex, TThreadData thread_data) {return TryLock(mutex, GetPid(thread_data));} + + inline void Lock(TRecMutex *mutex) {Lock(mutex, GetPid());} + + inline void Lock(TRecMutex *mutex, TThreadData thread_data) {Lock(mutex, GetPid(thread_data));} + + inline bool LockTime(TRecMutex *mutex, int time) {return LockTime(mutex, time, GetPid());} + + inline bool LockTime(TRecMutex *mutex, int time, TThreadData thread_data) + {return LockTime(mutex, time, GetPid(thread_data));} + + inline void UnLock(TRecMutex *mutex) {UnLock(mutex, GetPid());} + + inline void UnLock(TRecMutex *mutex, TThreadData thread_data) {UnLock(mutex, GetPid(thread_data));} + + inline int GetThreadNumber() {return _ThreadNumber;} + +// Constants from fasm. + +#include "kos_func.inc" + +// Functions. + + unsigned char _HashByte(unsigned int value); + unsigned short _HashWord(unsigned int value); + unsigned int _HashDword(unsigned int value); + + void _GetStartData(TStartData &start_data, TThreadData thread_data) + { + start_data.Left = (unsigned short)((unsigned long)thread_data[KOLIBRI_THREAD_DATA_X] >> 16); + start_data.Width = (unsigned short)((unsigned long)thread_data[KOLIBRI_THREAD_DATA_X]); + start_data.Top = (unsigned short)((unsigned long)thread_data[KOLIBRI_THREAD_DATA_Y] >> 16); + start_data.Height = (unsigned short)((unsigned long)thread_data[KOLIBRI_THREAD_DATA_Y]); + GetWindowData(start_data.WinData, thread_data); + } + + void _SetStartData(const TStartData &start_data, TThreadData thread_data) + { + (unsigned long&)thread_data[KOLIBRI_THREAD_DATA_X] = + ((unsigned int)start_data.Left << 16) | start_data.Width; + (unsigned long&)thread_data[KOLIBRI_THREAD_DATA_Y] = + ((unsigned int)start_data.Top << 16) | start_data.Height; + SetWindowData(start_data.WinData, thread_data); + } + + void _ApplyCommonColors(TWindowData &win_data) + { + unsigned int colors[10]; + ReadCommonColors(colors); + win_data.WindowColor = colors[5]; + win_data.HeaderColor = colors[1]; + win_data.BorderColor = colors[0]; + win_data.TitleColor = colors[4]; + } + + void _SetValueFunctionPriority(void *beg, int n) + { + int k, i; + unsigned char num[256]; + for (i = 0; i < 256; i++) num[i] = 0; + for (k = 0; k < n; k++) + { + i = ((unsigned char*)beg + 6*k)[1]; + ((unsigned char*)beg + 6*k)[0] = num[i]; + if (num[i] != 255) num[i]++; + } + } + + void _CallFunctionPriority(void *beg, void *end, bool reverse = false) + { + struct _Local + { + static int cmp(void *beg, int i, int j) + { + unsigned char *x = (unsigned char*)beg + 6*i; + unsigned char *y = (unsigned char*)beg + 6*j; + if (*(unsigned short*)x < *(unsigned short*)y) return -1; + if (*(unsigned short*)x > *(unsigned short*)y) return 1; + return 0; + } + + static void swap(void *beg, int i, int j) + { + unsigned char *x = (unsigned char*)beg + 6*i; + unsigned char *y = (unsigned char*)beg + 6*j; + short s; + int t; + s = *(short*)x; *(short*)x = *(short*)y; *(short*)y = s; + x += 2; y += 2; + t = *(int*)x; *(int*)x = *(int*)y; *(int*)y = t; + } + + static void call(void *beg, int i) + { + unsigned char *x = (unsigned char*)beg + 6*i; + (*(void(**)())(x+2))(); + } + }; + + if (!beg || !end || end <= beg) return; + int i, j, k, m, n; + n = ((unsigned char*)end - (unsigned char*)beg) / 6; + if (n <= 0) return; + _SetValueFunctionPriority(beg, n); + m = n; k = n; + while (m > 1) + { + if (k > 0) k--; + else _Local::swap(beg, 0, --m); + j = k; + for (;;) + { + i = j; + if (2*i + 1 >= m) break; + if (_Local::cmp(beg, 2*i + 1, j) > 0) j = 2*i + 1; + if (2*i + 2 < m && _Local::cmp(beg, 2*i + 2, j) > 0) j = 2*i + 2; + if (i == j) break; + _Local::swap(beg, i, j); + } + } + if (!reverse) + { + for (k = 0; k < n; k++) _Local::call(beg, k); + } + else + { + for (k = n-1; k >= 0; k--) _Local::call(beg, k); + } + } + + bool _CallStart(TThreadData thread_data, void *init = 0, void *init_end = 0) + { + struct _TThreadDataTemplate + { + unsigned int data[12]; + }; + static const _TThreadDataTemplate _ThreadDataTemplate = + {{3, 0x00320100, 0x00320100, 0x33FFFFFF, 0x806060FF, 0x00000000, 0x00FFFF40, 0, 0, 0, -1, -1}}; + + unsigned int pid = GetPid(); + volatile TThreadData *thread_table_item; + Lock(&_ThreadMutex); + if (_ExitProcessNow) ExitProcess(); + thread_table_item = &_ThreadTable[_HashByte(pid)]; + thread_data[KOLIBRI_THREAD_DATA_NEXT] = (void*)*thread_table_item; + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_PID] = pid; + *(_TThreadDataTemplate*)(thread_data + KOLIBRI_THREAD_DATA_FLAG) = _ThreadDataTemplate; + *thread_table_item = thread_data; + UnLock(&_ThreadMutex); + if (_ExitProcessNow) ExitProcess(); + _CallFunctionPriority(init, init_end, false); + TStartData start_data; + _GetStartData(start_data, thread_data); + _ApplyCommonColors(start_data.WinData); + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_FLAG] |= 0x40000000; + thread_data[KOLIBRI_THREAD_DATA_TITLE] = (void*)(&start_data); + if (!KolibriOnStart(start_data, thread_data)) return false; + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_FLAG] &= ~0x40000000; + _SetStartData(start_data, thread_data); + return true; + } + + void _RemoveThreadData(TThreadData thread_data, void *exit = 0, void *exit_end = 0) + { + _CallFunctionPriority(exit, exit_end, true); + volatile TThreadData *thread_table_item; + Lock(&_ThreadMutex); + if (_ExitProcessNow) ExitProcess(); + thread_table_item = &_ThreadTable[_HashByte(GetPid(thread_data))]; + while (*thread_table_item) + { + if (*thread_table_item == thread_data) + { + *thread_table_item = (TThreadData)thread_data[KOLIBRI_THREAD_DATA_NEXT]; + break; + } + thread_table_item = (TThreadData*)(*thread_table_item + KOLIBRI_THREAD_DATA_NEXT); + } + UnLock(&_ThreadMutex); + if (_ExitProcessNow) ExitProcess(); + } + + void GetWindowData(TWindowData &win_data, TThreadData thread_data) + { + if ((unsigned int)thread_data[KOLIBRI_THREAD_DATA_FLAG] & 0x40000000) + { + win_data = ((TStartData*)thread_data[KOLIBRI_THREAD_DATA_TITLE])->WinData; + return; + } + win_data.WindowType = (unsigned short)((unsigned int)thread_data[KOLIBRI_THREAD_DATA_C_WINDOW] >> 24); + win_data.HeaderType = (unsigned short)((unsigned int)thread_data[KOLIBRI_THREAD_DATA_C_HEADER] >> 24); + win_data.WindowColor = (unsigned int)thread_data[KOLIBRI_THREAD_DATA_C_WINDOW] & 0xFFFFFF; + win_data.HeaderColor = (unsigned int)thread_data[KOLIBRI_THREAD_DATA_C_HEADER] & 0xFFFFFF; + win_data.BorderColor = (unsigned int)thread_data[KOLIBRI_THREAD_DATA_C_BORDER] & 0xFFFFFF; + win_data.TitleColor = (unsigned int)thread_data[KOLIBRI_THREAD_DATA_C_TITLE] & 0xFFFFFF; + win_data.Title = (char*)thread_data[KOLIBRI_THREAD_DATA_TITLE]; + } + + void SetWindowData(const TWindowData &win_data, TThreadData thread_data) + { + if ((unsigned int)thread_data[KOLIBRI_THREAD_DATA_FLAG] & 0x40000000) + { + ((TStartData*)thread_data[KOLIBRI_THREAD_DATA_TITLE])->WinData = win_data; + return; + } + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_C_WINDOW] = + ((unsigned int)win_data.WindowType << 24) | (win_data.WindowColor & 0xFFFFFF); + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_C_HEADER] = + ((unsigned int)win_data.HeaderType << 24) | (win_data.HeaderColor & 0xFFFFFF); + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_C_BORDER] = win_data.BorderColor & 0xFFFFFF; + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_C_TITLE] = win_data.TitleColor & 0xFFFFFF; + thread_data[KOLIBRI_THREAD_DATA_TITLE] = (void*)win_data.Title; + Invalidate(1, thread_data); + } + + void CloseWindow(TThreadData thread_data) + { + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_FLAG] |= 0x80000000; + } + + void Invalidate(int frame, TThreadData thread_data) + { + if (frame < 0) return; + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_FLAG] |= (frame ? 3 : 1); + } + + void* GetPicture(unsigned short &width, unsigned short &height, TThreadData thread_data) + { + width = (unsigned short)((unsigned int)thread_data[KOLIBRI_THREAD_DATA_SZ_PICT] >> 16); + height = (unsigned short)((unsigned int)thread_data[KOLIBRI_THREAD_DATA_SZ_PICT]); + return (void*)thread_data[KOLIBRI_THREAD_DATA_PICTURE]; + } + + void SetPicture(void *picture, unsigned short width, unsigned short height, TThreadData thread_data) + { + thread_data[KOLIBRI_THREAD_DATA_PICTURE] = (void*)picture; + (unsigned int&)thread_data[KOLIBRI_THREAD_DATA_SZ_PICT] = + (width == 0 || height == 0) ? 0 : (((unsigned int)width << 16) | height); + Invalidate(0, thread_data); + } + + int _GetSkinHeader(); + + void GetBorderHeader(unsigned short &border_size, unsigned short &header_size, TThreadData thread_data) + { + int win_type = ((unsigned int)thread_data[KOLIBRI_THREAD_DATA_FLAG] & 0x40000000) ? + ((TStartData*)thread_data[KOLIBRI_THREAD_DATA_TITLE])->WinData.WindowType : + ((unsigned int)thread_data[KOLIBRI_THREAD_DATA_C_WINDOW] >> 24); + border_size = KOLIBRI_BORDER_SIZE; + header_size = short(((win_type & 15) == 3) ? _GetSkinHeader() : KOLIBRI_HEADER_SIZE); + } + + void GetClientSize(unsigned short &width, unsigned short &height, + int win_width, int win_height, TThreadData thread_data) + { + const int MAX_SIZE = 32767; + unsigned short border_size, header_size; + GetBorderHeader(border_size, header_size, thread_data); + win_width -= 2 * border_size; + win_height -= border_size + header_size; + if (win_width < 0) win_width = 0; + else if (win_width > MAX_SIZE) win_width = MAX_SIZE; + if (win_height < 0) win_height = 0; + else if (win_height > MAX_SIZE) win_height = MAX_SIZE; + width = (unsigned short)win_width; + height = (unsigned short)win_height; + } + + void GetMousePosPicture(short &x, short &y) + { + unsigned short dx, dy; + GetMousePosition(x, y); + GetBorderHeader(dx, dy); + x -= dx; y -= dy; + } +} + +#else // def __KOLIBRI__ + +namespace Kolibri +{ + struct TMutex + { + unsigned int mut; + + TMutex(); + ~TMutex(); + }; +#undef KOLIBRI_MUTEX_INIT +#define KOLIBRI_MUTEX_INIT TMutex() + + struct TRecMutex + { + unsigned int mut; + + TRecMutex(); + ~TRecMutex(); + }; +#undef KOLIBRI_REC_MUTEX_INIT +#define KOLIBRI_REC_MUTEX_INIT TRecMutex() +} + +#endif // else: def __KOLIBRI__ + +#endif // ndef __KOLIBRI_H_INCLUDED_ + diff --git a/programs/bcc32/include/kos_file.h b/programs/bcc32/include/kos_file.h new file mode 100644 index 0000000000..0a7e3c79b8 --- /dev/null +++ b/programs/bcc32/include/kos_file.h @@ -0,0 +1,278 @@ +#ifndef __KOLIBRI_FILE_H_INCLUDED_ +#define __KOLIBRI_FILE_H_INCLUDED_ + +#include "kolibri.h" +#include "kos_heap.h" + +// Kolibri file interface. + +namespace Kolibri // All kolibri functions, types and data are nested in the (Kolibri) namespace. +{ + struct _FileDataStruct; + typedef _FileDataStruct *TFileData; + + TFileData FileOpen(const char *name, unsigned int buffer_length = 1024); + int FileClose(TFileData file_data); + bool FileEof(TFileData file_data); + unsigned int FileGetPosition(TFileData file_data); + void FileSetPosition(TFileData file_data, unsigned int pos); + void FileReset(TFileData file_data); + unsigned int FileGetLength(TFileData file_data); + int FileTestRead(TFileData file_data); + int FileRead(TFileData file_data, void *mem, int size); +} + +#ifdef __KOLIBRI__ + +namespace Kolibri +{ +// Define the file data structure. + + struct _FileDataStruct + { + unsigned int length; + unsigned int position; + unsigned int *buffer; + unsigned int access_param[5]; + + enum {PosName = (unsigned int)(((_FileDataStruct*)0)->access_param + 5)}; + }; + +// Inline functions. + + inline bool FileEof(TFileData file_data) + { + return file_data && file_data->position >= file_data->length; + } + + inline unsigned int FileGetPosition(TFileData file_data) + { + return file_data ? file_data->position : 0; + } + + inline void FileReset(TFileData file_data) + { + if (!file_data) return; + file_data->length = -1; + file_data->position = 0; + if (file_data->buffer) file_data->buffer[1] = 0; + } + +// Functions. + + int _FileAccess(void *file_access_param); + + TFileData FileOpen(const char *name, unsigned int buffer_length) + { + if (!name || !name[0]) return 0; + unsigned int name_len = StrLen(name) + 1; + unsigned int data_len = (_FileDataStruct::PosName + name_len + 3) & ~3; + buffer_length = (buffer_length / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE; + if (buffer_length) data_len += buffer_length + 2*sizeof(unsigned int); + TFileData file = (TFileData)Alloc(_FileDataStruct::PosName + data_len); + if (!file) return 0; + file->length = -1; + file->position = 0; + if (buffer_length) + { + file->buffer = (unsigned int*)((char*)file + data_len) - 2; + file->buffer[0] = buffer_length; + file->buffer[1] = 0; + } + MemCopy(file->access_param + 5, name, name_len); + unsigned int attr[40/4]; + file->access_param[0] = 5; + file->access_param[1] = 0; + file->access_param[2] = 0; + file->access_param[3] = 0; + file->access_param[4] = (int)attr; + _FileAccess(file->access_param); + file->length = attr[32/4]; + return file; + } + + int FileClose(TFileData file_data) + { + if (!file_data) return -1; + Free(file_data); + return 0; + } + + void FileSetPosition(TFileData file_data, unsigned int pos) + { + if (!file_data) return; + if (file_data->buffer && file_data->buffer[1]) + { + if (pos >= file_data->position && pos < file_data->position + file_data->buffer[1]) + { + file_data->buffer[1] -= pos - file_data->position; + } + else file_data->buffer[1] = 0; + } + file_data->position = pos; + } + + int _FileReadBuffer(TFileData file_data, void *mem, int size, void *temp_mem = 0) + { + unsigned int *buffer; + if (!file_data || !mem || size <= 0) return -1; + if (file_data->buffer) buffer = file_data->buffer; + else if (temp_mem) + { + buffer = (unsigned int*)((char*)temp_mem + KOLIBRI_FILE_BLOCK_SIZE); + } + else return 0; + if (!buffer[1]) return 0; + if (file_data->position >= file_data->length) + { + buffer[1] = 0; + return 0; + } + unsigned int buf_size = file_data->length - file_data->position; + if (buf_size > buffer[1]) buf_size = buffer[1]; + if ((unsigned int)size >= buf_size) size = buf_size; + MemCopy(mem, (char*)buffer - buffer[1], size); + file_data->position += size; + if ((unsigned int)size >= buf_size) buffer[1] = 0; + else buffer[1] -= size; + return size; + } + + int _FileReadSystem(TFileData file_data, void *mem, int size) + { + int res; + unsigned int len0, len1; + size /= KOLIBRI_FILE_BLOCK_SIZE; + if (!file_data || !mem || size <= 0) return -1; + file_data->access_param[0] = 0; + file_data->access_param[1] = (file_data->position / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE; + file_data->access_param[2] = 0; + file_data->access_param[3] = size * KOLIBRI_FILE_BLOCK_SIZE; + file_data->access_param[4] = (unsigned int)mem; + res = _FileAccess(file_data->access_param); + if (res != 0 && res != 6) return (res & 255) - 1024; + if (file_data->length <= file_data->position) return 0; + len0 = file_data->length - file_data->position; + len1 = size * KOLIBRI_FILE_BLOCK_SIZE - (file_data->position % KOLIBRI_FILE_BLOCK_SIZE); + return (len0 <= len1) ? len0 : len1; + } + + int _FileBufferSystem(TFileData file_data, void *&temp_mem) + { + int res; + unsigned int *buffer; + if (!file_data) return -1; + if (file_data->buffer) buffer = file_data->buffer; + else + { + if (!temp_mem) + { + temp_mem = Alloc(KOLIBRI_FILE_BLOCK_SIZE + 2*sizeof(unsigned int)); + if (!temp_mem) return -10; + } + buffer = (unsigned int*)((char*)temp_mem + KOLIBRI_FILE_BLOCK_SIZE); + buffer[0] = KOLIBRI_FILE_BLOCK_SIZE; + } + buffer[1] = buffer[0]; + res = _FileReadSystem(file_data, (char*)buffer - buffer[1], buffer[1]); + if (res < 0) buffer[1] = 0; + else buffer[1] -= file_data->position % KOLIBRI_FILE_BLOCK_SIZE; + return res; + } + + int FileTestRead(TFileData file_data) + { + int res; + void *temp_mem = 0; + if (!file_data) return -1; + if (file_data->buffer && file_data->buffer[1]) return 0; + res = _FileBufferSystem(file_data, temp_mem); + if (temp_mem) Free(temp_mem); + return (res < 0) ? res : 0; + } + + int FileRead(TFileData file_data, void *mem, int size) + { + int tlen, res, read_len; + void *temp_mem = 0; + res = _FileReadBuffer(file_data, mem, size); + if (res < 0 || res >= size) return res; + read_len = res; + mem = (char*)mem + res; + size -= res; + tlen = file_data->position % KOLIBRI_FILE_BLOCK_SIZE; + if (tlen) + { + res = _FileBufferSystem(file_data, temp_mem); + if (res < 0) + { + if (temp_mem) Free(temp_mem); + return read_len ? read_len : res; + } + res = _FileReadBuffer(file_data, mem, size); + read_len += res; + if (res >= size || file_data->length <= file_data->position || + file_data->length - file_data->position <= res) + { + if (temp_mem) Free(temp_mem); + return read_len; + } + mem = (char*)mem + res; + size -= res; + } + if (size >= (file_data->buffer ? file_data->buffer[0] : KOLIBRI_FILE_BLOCK_SIZE)) + { + res = _FileReadSystem(file_data, mem, size); + if (res < 0) + { + if (temp_mem) Free(temp_mem); + return read_len ? read_len : res; + } + file_data->position += res; + read_len += res; + if (res < (size / KOLIBRI_FILE_BLOCK_SIZE) * KOLIBRI_FILE_BLOCK_SIZE) + { + if (temp_mem) Free(temp_mem); + return read_len; + } + mem = (char*)mem + res; + size -= res; + } + if (size) + { + res = _FileBufferSystem(file_data, temp_mem); + if (res < 0) + { + if (temp_mem) Free(temp_mem); + return read_len ? read_len : res; + } + read_len += _FileReadBuffer(file_data, mem, size, temp_mem); + } + if (temp_mem) Free(temp_mem); + return read_len; + } + +// Inline functions. + + inline unsigned int FileGetLength(TFileData file_data) + { + if (!file_data) return -1; + if (file_data->length == -1) FileTestRead(file_data); + return file_data->length; + } +} + +#else // def __KOLIBRI__ + +namespace Kolibri +{ + struct _FileDataStruct + { + unsigned int data; + }; +} + +#endif // else: def __KOLIBRI__ + +#endif // ndef __KOLIBRI_FILE_H_INCLUDED_ + diff --git a/programs/bcc32/include/kos_func.inc b/programs/bcc32/include/kos_func.inc new file mode 100644 index 0000000000..1a6cdab0a6 --- /dev/null +++ b/programs/bcc32/include/kos_func.inc @@ -0,0 +1,1057 @@ +;const int +KOLIBRI_BORDER_SIZE = 4; +;const int +KOLIBRI_HEADER_SIZE = 20; + +;const int +KOLIBRI_THREAD_DATA_USER = 0; // Thread data begin from the user dword +;const int +KOLIBRI_THREAD_DATA_ST_BEGIN = 1; // Stack beginning follows after the user dword +;const int +KOLIBRI_THREAD_DATA_NEXT = 2; +;const int +KOLIBRI_THREAD_DATA_PID = 3; +;const int +KOLIBRI_THREAD_DATA_FLAG = 4; +;const int +KOLIBRI_THREAD_DATA_X = 5; +;const int +KOLIBRI_THREAD_DATA_Y = 6; +;const int +KOLIBRI_THREAD_DATA_C_WINDOW = 7; +;const int +KOLIBRI_THREAD_DATA_C_HEADER = 8; +;const int +KOLIBRI_THREAD_DATA_C_BORDER = 9; +;const int +KOLIBRI_THREAD_DATA_C_TITLE = 10; +;const int +KOLIBRI_THREAD_DATA_TITLE = 11; +;const int +KOLIBRI_THREAD_DATA_PICTURE = 12; +;const int +KOLIBRI_THREAD_DATA_SZ_PICT = 13; +;const int +KOLIBRI_THREAD_DATA_LAST_SX = 14; +;const int +KOLIBRI_THREAD_DATA_LAST_SY = 15; +;const int +KOLIBRI_THREAD_DATA_LEN = 16; + +;const int +KOLIBRI_MUTEX_MAX_TIME_WAIT = 20; + +;const int +KOLIBRI_FILE_BLOCK_SIZE = 512; + +;const int +KOLIBRI_FILE_MEMORY_OS_NEED = 4096; + +;/*** + +macro segment name +{ + segment name + if name eq _init_ | name eq _INIT_ +Kolibri_SegmentInit: + else if name eq _exit_ | name eq _EXIT_ +Kolibri_SegmentExit: + end if +} + +macro endseg name +{ + if name eq _init_ | name eq _INIT_ +Kolibri_SegmentInitEnd: + else if name eq _exit_ | name eq _EXIT_ +Kolibri_SegmentExitEnd: + end if + endseg name +} + +macro Kolibri_Put_MovEaxVal_Ret address,val +{ + mov byte [address],0xB8 + mov dword [address+4],0xC089C300 + mov dword [address+1],val +} + +proc @Kolibri@Main$qv + and esp,not 3 + sub esp,1024 + mov eax,9 + mov ebx,esp + mov ecx,-1 + int 0x40 + mov ebx,[esp+26] + mov edx,[esp+30] + lea eax,[ebx-0x20] + add esp,1024 + cmp esp,eax + cmova esp,eax + and esp,not 3 +if defined @Kolibri@CommandLine + mov byte [@Kolibri@CommandLine+256], 0 +end if + xor eax,eax + cld + mov edi,@Kolibri@_ThreadTable + mov ecx,256 + rep stos dword [edi] + mov esi,@Kolibri@GetPid$qv + mov edi,@Kolibri@_ThreadSavedBegProc + movs dword [edi],[esi] + movs dword [edi],[esi] + mov esi,@Kolibri@GetThreadData$qv + movs dword [edi],[esi] + movs dword [edi],[esi] + Kolibri_Put_MovEaxVal_Ret @Kolibri@GetPid$qv,edx +if defined KolibriHeapInit + mov ecx,esp + push ebx + push ecx + push U_END + call KolibriHeapInit ; Initialize a dynamic heap and create new memory in its begin. + pop ecx ; Parameters: begin of a new heap, end of data to create in + mov [esp+4],eax ; the begin of a heap. Return address of the created data. + mov dword [esp],0 +else + xor eax,eax + push eax + push eax +end if + call @Kolibri@ThreadMain$qpvt1 +.ThreadFinish: + add esp,8 +if defined KolibriHeapFreeAndThreadFinish + test eax,eax + jz .ThreadFinish_end + push dword @Kolibri@_ExitProcessNow + push eax + call KolibriHeapFreeAndThreadFinish ; Free the given memory and finish the thread, +end if ; should exit process if second argument points to not zero. +.ThreadFinish_end: + or eax,-1 + int 0x40 +endp + +proc @Kolibri@ThreadMain$qpvt1 + xchg ebx,[esp+4] + xchg ebp,[esp+8] + push esi edi + sub esp,KOLIBRI_THREAD_DATA_LEN*4 + mov [esp],ebx + mov [esp+4],ebp + mov eax,40 + mov ebx,0x27 + int 0x40 + mov ebx,esp + cmp byte [@Kolibri@_ThreadSavedBegProc],0x90 + jz .main_else_first_check + Kolibri_Put_MovEaxVal_Ret @Kolibri@GetThreadData$qv,esp +if defined Kolibri_SegmentInit & defined Kolibri_SegmentInitEnd + push Kolibri_SegmentInitEnd + push Kolibri_SegmentInit + jmp .main_after_first_check +end if +.main_else_first_check: + xor eax,eax + push eax eax +.main_after_first_check: + push ebx + call @@Kolibri@_CallStart$qppvpvt2 + add esp,12 + test al,al + jnz .main_test_close_first + jmp .main_end +.main_close_first: + btr dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],31 + push esp + call @@KolibriOnClose$qppv + pop ecx + test al,al + jnz .main_end +.main_test_close_first: + cmp dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],0 + jl .main_close_first +; push esp +; push dword 1 +; call @Kolibri@Redraw$qippv +; add esp,8 +.main_paint_msg: + or dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],3 + sub esp,1024 + mov eax,9 + mov ebx,esp + mov ecx,-1 + int 0x40 + mov eax,[esp+34] + mov ebx,[esp+38] + mov ecx,[esp+42] + mov edx,[esp+46] + add esp,1024 + cmp ecx,[esp+KOLIBRI_THREAD_DATA_LAST_SX*4] + jnz .main_size + cmp edx,[esp+KOLIBRI_THREAD_DATA_LAST_SY*4] + jz .main_paint +.main_size: + mov [esp+KOLIBRI_THREAD_DATA_LAST_SX*4],ecx + mov [esp+KOLIBRI_THREAD_DATA_LAST_SY*4],edx + push edx + push ecx + push ebx + push eax + lea ecx,[esp+16] + mov edx,esp + push ecx + push edx + call @@KolibriOnSize$qpippv + add esp,24 + test dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],3 + jz .main_cycle +.main_paint: + cmp dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],0 + jl .main_close + push esp + push dword 0 + call @Kolibri@Redraw$qippv + add esp,8 +.main_cycle: + mov eax,11 +.main_message: + cmp dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],0 + jl .main_close + int 0x40 + test eax,eax + jnz .main_on_message + cmp dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],0 + jne .main_paint + push esp + call @@KolibriOnIdle$qppv + pop ecx + test eax,eax + jz .main_cycle + jl .main_wait_message + mov ebx,eax + mov eax,23 + jmp .main_message +.main_wait_message: + mov eax,10 + jmp .main_message +.main_key_press: + push esp + call @@KolibriOnKeyPress$qppv + pop ecx + jmp .main_cycle +.main_mouse: + push esp + call @@KolibriOnMouse$qppv + pop ecx + jmp .main_cycle +.main_on_message: + dec eax + jz .main_paint_msg + dec eax + jz .main_key_press + cmp eax,4 + jz .main_mouse + dec eax + jnz .main_cycle +.main_button: + mov eax,17 + int 0x40 + test al,al + jnz .main_cycle +.main_close: + btr dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],31 + push esp + call @@KolibriOnClose$qppv + pop ecx + test al,al + jz .main_button +.main_end: + mov ebx,esp + lock dec dword [@Kolibri@_ThreadNumber] +if defined Kolibri_SegmentExit & defined Kolibri_SegmentExitEnd + jnz .main_else_last_check + push Kolibri_SegmentExitEnd + push Kolibri_SegmentExit + jmp .main_after_last_check +end if +.main_else_last_check: + xor eax,eax + push eax + push eax +.main_after_last_check: + push ebx + call @@Kolibri@_RemoveThreadData$qppvpvt2 + add esp,12 + lock inc dword [@Kolibri@_ThreadScanCount+4] + mov ebx,1 + jmp .main_end_wait +.main_end_wait_loop: + mov eax,5 + int 0x40 + shl ebx,1 + cmp ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT + jna .main_end_wait + mov ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT +.main_end_wait: + cmp dword [@Kolibri@_ExitProcessNow],0 + jnz @Kolibri@ExitProcess$qv + cmp dword [@Kolibri@_ThreadScanCount],0 + jnz .main_end_wait_loop + lock dec dword [@Kolibri@_ThreadScanCount+4] + mov ebp,[esp+4] + mov ebx,[esp] + add esp,KOLIBRI_THREAD_DATA_LEN*4 + mov eax,ebp + pop edi esi + xchg ebp,[esp+8] + xchg ebx,[esp+4] + ret +endp + +macro call func +{ + if func eq __chkstk + sub esp,eax + else + call func + end if +} + +proc @Kolibri@Redraw$qippv + push ebp + mov ebp,[esp+12] + mov edx,[ebp+KOLIBRI_THREAD_DATA_FLAG*4] + cmp dword [esp+8],0 + jl .redraw_only_inv + jz .redraw_no_frame + or dl,2 +.redraw_no_frame: + bt edx,30 + jnc .redraw_begin + or dl,1 + mov [ebp+KOLIBRI_THREAD_DATA_FLAG*4],edx + jmp .redraw_end +.redraw_only_inv: + test dl,3 + jnz .redraw_no_frame +.redraw_end: + pop ebp + ret +.redraw_begin: + push ebx esi edi + and dword [ebp+KOLIBRI_THREAD_DATA_FLAG*4],0xFFFFFFFC + mov eax,12 + mov ebx,1 + int 0x40 + test dl,2 + jz .redraw_picture + mov eax,48 + mov ebx,4 + int 0x40 + mov ebx,[ebp+KOLIBRI_THREAD_DATA_X*4] + add ebx,2*5-1 + mov ecx,[ebp+KOLIBRI_THREAD_DATA_Y*4] + add cx,ax + add ecx,5-1 + mov edx,[ebp+KOLIBRI_THREAD_DATA_C_WINDOW*4] + mov edi,[ebp+KOLIBRI_THREAD_DATA_TITLE*4] + xor eax,eax + int 0x40 +.redraw_picture: + call @@KolibriOnPaint$qv +.redraw_end_draw: + mov eax,12 + mov ebx,2 + int 0x40 + pop edi esi ebx ebp + ret +endp + +proc @Kolibri@MoveWindow$qxpxi uses ebx esi + mov eax,[esp+12] + mov ebx,[eax] + mov ecx,[eax+4] + mov edx,[eax+8] + mov esi,[eax+12] + mov eax,67 + int 0x40 + ret +endp + +;proc @Kolibri@Abort$qv +; push dword [@Kolibri@DebugPrefix] +; call @Kolibri@DebugPutString$qpxc +; mov dword [esp],Kolibri_abort_string +; call @Kolibri@DebugPutString$qpxc +; pop ecx +proc @Kolibri@ExitProcess$qv + lock bts dword [@Kolibri@_ExitProcessNow],0 + jc .exit_process_wait + sub esp,1024 + mov eax,9 + mov ebx,esp + mov ecx,-1 + int 0x40 + mov esi,eax + mov edi,[esp+30] +.exit_process_loop: + mov eax,9 + mov ebx,esp + mov ecx,esi + int 0x40 + mov eax,[esp+30] + cmp eax,edi + jz .exit_process_continue + mov ebx,eax + or bl,15 + inc ebx + jz .exit_process_continue + mov ebx,eax + call Kolibri_HashInt + movzx eax,al + mov eax,dword [@Kolibri@_ThreadTable+eax*4] + jmp .exit_process_test +.exit_process_next: + mov eax,dword [eax+KOLIBRI_THREAD_DATA_NEXT*4] +.exit_process_test: + test eax,eax + jz .exit_process_continue + cmp ebx,[eax+KOLIBRI_THREAD_DATA_PID*4] + jnz .exit_process_next + mov eax,18 + mov ebx,2 + mov ecx,esi + int 0x40 +.exit_process_continue: + dec esi + jnl .exit_process_loop + add esp,1024 + mov dword [@Kolibri@_ExitProcessNow],-1 +if defined EMULATOR + int3 + call 0x76543210 +end if +.exit_process_end: + mov dword [@Kolibri@_ThreadMutex],0 + or eax,-1 + int 0x40 +.exit_process_wait: + mov eax,5 + mov ebx,1 +.exit_process_wait_loop: + cmp dword [@Kolibri@_ExitProcessNow],0 + jl .exit_process_end + int 0x40 + shl ebx,1 + cmp ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT + jna .exit_process_wait_loop + mov ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT + jmp .exit_process_wait_loop +endp + +proc @Kolibri@ExitThread$qppv,@Kolibri@ThreadMain$qpvt1 + mov esp,[esp+4] + jmp Kolibri_main_end +endp + +proc @Kolibri@ReturnMessageLoop$qppv,@Kolibri@ThreadMain$qpvt1 + mov esp,[esp+4] + bt dword [esp+KOLIBRI_THREAD_DATA_FLAG*4],30 + jc Kolibri_main_end + jmp Kolibri_main_cycle +endp + +proc @Kolibri@Delay$qui uses ebx + mov eax,5 + mov ebx,[esp+8] + int 0x40 + ret +endp + +proc @Kolibri@Clock$qv uses ebx + mov eax,26 + mov ebx,9 + int 0x40 + ret +endp + +proc @Kolibri@GetPackedTime$qv + mov eax,3 + int 0x40 + ret +endp + +proc @Kolibri@GetTime$qpi + mov eax,3 + int 0x40 + mov edx,[esp+4] + movzx ecx,al + shr ecx,4 + and al,0x0F + imul ecx,10 + add cl,al + mov dword [edx+8],ecx + mov cl,ah + shr ecx,4 + and ah,0x0F + imul ecx,10 + add cl,ah + mov dword [edx+4],ecx + bswap eax + mov cl,ah + shr ecx,4 + and ah,0x0F + imul ecx,10 + add cl,ah + mov dword [edx],ecx + ret +endp + +proc @Kolibri@GetPackedDate$qv + mov eax,29 + int 0x40 + ret +endp + +proc @Kolibri@GetDate$qpi + mov eax,29 + int 0x40 + mov edx,[esp+4] + movzx ecx,al + shr ecx,4 + and al,0x0F + imul ecx,10 + add cl,al + mov dword [edx+4],ecx + mov cl,ah + shr ecx,4 + and ah,0x0F + imul ecx,10 + add cl,ah + mov dword [edx],ecx + bswap eax + mov cl,ah + shr ecx,4 + and ah,0x0F + imul ecx,10 + add cl,ah + mov dword [edx+8],ecx + ret +endp + +proc @Kolibri@ReadCommonColors$qpui uses ebx + mov eax,48 + mov ebx,3 + mov ecx,[esp+8] + mov edx,40 + int 0x40 + ret +endp + +proc @Kolibri@DrawText$qssipxc uses ebx + mov eax,4 + mov ebx,[esp+8-2] + mov bx,[esp+12] + mov ecx,[esp+16] + or ecx,0x80000000 + mov edx,[esp+20] + int 0x40 + ret +endp + +proc @Kolibri@GetProcessInfo$qpuipct1t1piui uses ebx esi edi + sub esp,1024 + mov eax,9 + mov ebx,esp + mov ecx,[1024+12+24+esp] + int 0x40 + xor edi,edi + or edi,[1024+12+4+esp] + jz .get_proc_info_no_usecpu + mov ecx,[esp] + mov [edi],ecx + xor edi,edi +.get_proc_info_no_usecpu: + or edi,[1024+12+8+esp] + jz .get_proc_info_no_name + lea esi,[esp+10] + cld + movs dword [edi],[esi] + movs dword [edi],[esi] + movs dword [edi],[esi] + mov byte [edi],0 + xor edi,edi +.get_proc_info_no_name: + or edi,[1024+12+12+esp] + jz .get_proc_info_no_mem + mov ecx,[esp+26] + mov [edi],ecx + xor edi,edi +.get_proc_info_no_mem: + or edi,[1024+12+16+esp] + jz .get_proc_info_no_pid + mov ecx,[esp+30] + mov [edi],ecx + xor edi,edi +.get_proc_info_no_pid: + or edi,[1024+12+20+esp] + jz .get_proc_info_no_rect + lea esi,[esp+34] + cld + movs dword [edi],[esi] + movs dword [edi],[esi] + movs dword [edi],[esi] + movs dword [edi],[esi] + xor edi,edi +.get_proc_info_no_rect: + add esp,1024 + ret +endp + +proc @Kolibri@GetPid$qv uses ebx + sub esp,1024 + mov eax,9 + mov ebx,esp + mov ecx,-1 + int 0x40 + mov eax,[esp+30] + add esp,1024 + ret +endp + +proc @Kolibri@GetPid$qppv + mov ecx,[esp+4] + mov eax,[ecx+KOLIBRI_THREAD_DATA_PID*4] + ret +endp + +proc @Kolibri@_HashByte$qui +@Kolibri@_HashWord$qui: +@Kolibri@_HashDword$qui: + mov eax,[esp+4] +Kolibri_HashInt: + mul dword [Kolibri_hash_int_val0] + xor eax,edx + bswap eax + mul dword [Kolibri_hash_int_val1] + shrd eax,edx,14 + bswap eax + lea eax,[eax+4*eax] + ror eax,9 + ret +endp + +Kolibri_hash_int_val0: + dd 0xA82F94C5 +Kolibri_hash_int_val1: + dd 0x9193780B + +proc @Kolibri@GetThreadData$qv + call @Kolibri@GetPid$qv + push eax + call @Kolibri@GetThreadData$qui + pop ecx + ret +endp + +proc @Kolibri@GetThreadData$qui + mov eax,[esp+4] + call Kolibri_HashInt + movzx eax,al + cmp dword [@Kolibri@_ThreadScanCount+4],0 + jnz .get_thread_data_wait +.get_thread_data_nowait: + lock inc dword [@Kolibri@_ThreadScanCount] + mov eax,dword [@Kolibri@_ThreadTable+eax*4] + mov ecx,[esp+4] + jmp .get_thread_data_test +.get_thread_data_loop: + mov eax,dword [eax+KOLIBRI_THREAD_DATA_NEXT*4] +.get_thread_data_test: + test eax,eax + jz .get_thread_data_end + cmp ecx,[eax+KOLIBRI_THREAD_DATA_PID*4] + jnz .get_thread_data_loop +.get_thread_data_end: + lock dec dword [@Kolibri@_ThreadScanCount] + ret +.get_thread_data_wait: + push eax ebx + mov eax,5 + mov ebx,1 +.get_thread_data_wait_loop: + int 0x40 + cmp dword [@Kolibri@_ThreadScanCount+4],0 + jz .get_thread_data_wait_end + shl ebx,1 + cmp ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT + jna .get_thread_data_wait_loop + mov ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT + jmp .get_thread_data_wait_loop +.get_thread_data_wait_end: + pop ebx eax + jmp .get_thread_data_nowait +endp + +proc @Kolibri@_GetSkinHeader$qv uses ebx + mov eax,48 + mov ebx,4 + int 0x40 + ret +endp + +proc @Kolibri@GetScreenSize$qrust1 + mov eax,14 + int 0x40 + mov ecx,[esp+8] + mov word [ecx],ax + mov ecx,[esp+4] + shr eax,16 + mov word [ecx],ax + ret +endp + +proc Kolibri_MutexLockNoWait + pop eax + xor al,al + ret +endp + +proc Kolibri_MutexLockWait uses ebx + mov eax,5 + xor ebx,ebx +.lock_wait_cycle: + int 0x40 + shl byte [ecx],1 + jz .lock_wait_cycle + mov al,1 + ret +endp + +proc Kolibri_MutexLockWaitTime + cmp dword [esp+12],0 + jng .MutexLockWait + push ebx edx + mov edx,[esp+20] + mov eax,26 + mov ebx,9 + int 0x40 + add edx,eax +.lock_wait_time_cycle: + mov eax,5 + xor ebx,ebx + int 0x40 + shl byte [ecx],1 + jnz .lock_wait_time_ret_true + mov eax,26 + mov ebx,9 + int 0x40 + cmp eax,edx + js .lock_wait_time_cycle + pop edx ebx eax + xor al,al + ret +.lock_wait_time_ret_true: + pop edx ebx + mov al,1 + ret +endp + +proc Kolibri_MutexLock + shl byte [ecx],1 + jnz .lock_first + call eax +.lock_first: + mov al,1 + ret +endp + +proc @Kolibri@TryLock$qp14Kolibri@TMutex + mov eax,Kolibri_MutexLockNoWait + mov ecx,[esp+4] + jmp Kolibri_MutexLock +endp + +proc @Kolibri@Lock$qp14Kolibri@TMutex + mov eax,Kolibri_MutexLockWait + mov ecx,[esp+4] + jmp Kolibri_MutexLock +endp + +proc @Kolibri@LockTime$qp14Kolibri@TMutexi + mov eax,Kolibri_MutexLockWaitTime + mov ecx,[esp+4] + jmp Kolibri_MutexLock +endp + +proc @Kolibri@UnLock$qp14Kolibri@TMutex + mov ecx,[esp+4] + shr byte [ecx],1 + jz .unlock_pause + ret +.unlock_pause: + mov byte [ecx],0x40 + push ebx + mov eax,5 + xor ebx,ebx + int 0x40 + pop ebx + ret +endp + +proc Kolibri_MutexLockRec + shl byte [ecx],1 + jng .lock_first + cmp dword [ecx+4],edx + jz .lock_rec_self + call eax +.lock_rec_first: + mov al,1 + mov dword [ecx+4],edx + ret +.lock_rec_self: + mov al,1 + add dword [ecx],0x100 + jc .lock_rec_overflow + ret +.lock_rec_overflow: + push dword [@Kolibri@DebugPrefix] + call @Kolibri@DebugPutString$qpxc + mov dword [esp],Kolibri_try_lock_rec_overflow_string + call @Kolibri@DebugPutString$qpxc + pop ecx + jmp @Kolibri@Abort$qv +endp + +proc @Kolibri@TryLock$qp16Kolibri@TRecMutexui + mov eax,Kolibri_MutexLockNoWait + mov ecx,[esp+4] + mov edx,[esp+8] + jmp Kolibri_MutexLockRec +endp + +proc @Kolibri@Lock$qp16Kolibri@TRecMutexui + mov eax,Kolibri_MutexLockWait + mov ecx,[esp+4] + mov edx,[esp+8] + jmp Kolibri_MutexLockRec +endp + +proc @Kolibri@LockTime$qp16Kolibri@TRecMutexiui + mov eax,Kolibri_MutexLockWaitTime + mov ecx,[esp+4] + mov edx,[esp+12] + jmp Kolibri_MutexLockRec +endp + +proc @Kolibri@UnLock$qp16Kolibri@TRecMutexui + mov ecx,[esp+4] + mov edx,[esp+8] + cmp dword [ecx+4],edx + jnz .unlock_rec_notlocked + sub dword [ecx],0x100 + jnc .unlock_rec_end + add dword [ecx],0x100 + shl byte [ecx],1 + shr byte [ecx],2 + jng .unlock_rec_pause +.unlock_rec_end: + ret +.unlock_rec_pause: + mov byte [ecx],0x20 + push ebx + mov eax,5 + xor ebx,ebx + int 0x40 + pop ebx + ret +.unlock_rec_notlocked: + push dword [@Kolibri@DebugPrefix] + call @Kolibri@DebugPutString$qpxc + mov dword [esp],Kolibri_unlock_rec_notlocked_string + call @Kolibri@DebugPutString$qpxc + pop ecx + jmp @Kolibri@Abort$qv +endp + +proc @Kolibri@DebugPutChar$qc + mov cl,byte [esp+4] + cmp cl,13 + jz .debug_put_char_ret + push ebx + cmp cl,10 + jz .debug_put_char_enter +.debug_put_char_after_cmp: + mov eax,63 + mov ebx,1 + int 0x40 + pop ebx +.debug_put_char_ret: + ret +.debug_put_char_enter: + mov cl,13 + mov eax,63 + mov ebx,1 + int 0x40 + mov cl,10 + jmp .debug_put_char_after_cmp +endp + +proc @Kolibri@DebugPutString$qpxc + push esi + push dword 0 + mov esi,dword [esp+12] + jmp .debug_put_string_test +.debug_put_string_loop: + mov dword [esp],eax + call @Kolibri@DebugPutChar$qc + inc esi +.debug_put_string_test: + xor eax,eax + or al,[esi] + test al,al + jnz .debug_put_string_loop + pop ecx esi + ret +endp + +proc @Kolibri@GetKey$qv + mov eax,2 + int 0x40 + test al,al + jnz .get_key_eof + movzx eax,ah + ret +.get_key_eof: + mov eax,-1 + ret +endp + +proc @Kolibri@GetMouseButton$qv uses ebx + mov eax,37 + mov ebx,2 + int 0x40 + ret +endp + +proc @Kolibri@GetMousePosition$qrst1o uses ebx + mov eax,37 + xor ebx,ebx + cmp byte [esp+16],0 + jnz .get_mouse_pos_absolute + inc ebx +.get_mouse_pos_absolute: + int 0x40 + mov ecx,[esp+12] + mov word [ecx],ax + mov ecx,[esp+8] + shr eax,16 + mov word [ecx],ax + ret +endp + +proc @Kolibri@WasThreadCreated$qv + cmp byte [@Kolibri@_ThreadSavedBegProc],0x90 + setz al + ret +endp + +proc @Kolibri@CreateThread$qpvuit1 + push ebx + mov edx,[esp+16] + mov ebx,[esp+12] + test edx,edx + jnz .create_thread_after_new +if defined KolibriHeapAlloc + cmp ebx,4096 + jnb .create_thread_alloc + mov ebx,STACKSIZE +.create_thread_alloc: + push ebx + call KolibriHeapAlloc ; Create new dynamic memory of the given size + pop ecx + test eax,eax + jnz .create_thread_mem_created +end if + or eax,-1 + jmp .create_thread_end +.create_thread_mem_created: + lea edx,[eax+ebx] +.create_thread_after_new: + neg ebx + jz .create_thread_test_first + add ebx,edx +.create_thread_test_first: + cmp byte [@Kolibri@_ThreadSavedBegProc],0x90 + jnz .create_thread_init +.create_thread_fill_stack: + lock inc dword [@Kolibri@_ThreadNumber] + and edx,not 3 + sub edx,12 + mov ecx,[esp+8] + mov dword [edx+8],ebx + mov dword [edx+4],ecx + mov dword [edx],Kolibri_ThreadFinish + mov eax,51 + mov ebx,1 + mov ecx,@Kolibri@ThreadMain$qpvt1 + int 0x40 + mov ebx,eax + or bl,15 + inc ebx + jnz .create_thread_end + lock dec dword [@Kolibri@_ThreadNumber] +if defined KolibriHeapFree + or ebx,[edx+8] + jz .create_thread_end + push ebx + call KolibriHeapFree ; Delete the given dynamic memory + pop ecx +end if +.create_thread_end: + pop ebx + ret +.create_thread_init: + push esi edi + cld + mov esi,@Kolibri@_ThreadSavedBegProc + mov edi,@Kolibri@GetPid$qv + movs dword [edi],[esi] + movs dword [edi],[esi] + mov edi,@Kolibri@GetThreadData$qv + movs dword [edi],[esi] + movs dword [edi],[esi] + mov eax,0x90909090 + mov edi,@Kolibri@_ThreadSavedBegProc + stos dword [edi] + stos dword [edi] + stos dword [edi] + stos dword [edi] + pop edi esi + jmp .create_thread_fill_stack +endp + +proc @Kolibri@_FileAccess$qpv uses ebx + mov eax,70 + mov ebx,[esp+8] + int 0x40 + mov ecx,[esp+8] + mov [ecx],ebx + ret +endp + +Kolibri_abort_string: + db 'Abnormal program termination.',10,0 +Kolibri_try_lock_rec_overflow_string: + db 'Recursive mutex lock count overflow.',10,0 +Kolibri_unlock_rec_notlocked_string: + db 'Recursive mutex unlock error.',10,0 + +include "kos_lib.inc" + +;/**/ + diff --git a/programs/bcc32/include/kos_heap.h b/programs/bcc32/include/kos_heap.h new file mode 100644 index 0000000000..b5dff0950a --- /dev/null +++ b/programs/bcc32/include/kos_heap.h @@ -0,0 +1,90 @@ +#ifndef __KOLIBRI_HEAP_H_INCLUDED_ +#define __KOLIBRI_HEAP_H_INCLUDED_ + +#include "kolibri.h" +#include "memheap.h" + +// Kolibri memory heap interface. + +namespace Kolibri // All kolibri functions, types and data are nested in the (Kolibri) namespace. +{ + void *Alloc(unsigned int size); + void *ReAlloc(void *mem, unsigned int size); + void Free(void *mem); +} + +#ifdef __KOLIBRI__ + +namespace Kolibri +{ + +// Global variables + + MemoryHeap::TFreeSpace _KolibriFreeSpace; + MemoryHeap::TMemBlock _KolibriMemBlock; + TMutex _MemHeapMutex = KOLIBRI_MUTEX_INIT; + +// Functions + + void *_HeapInit(void *begin, void *use_end, void *end) + { + MemoryHeap::InitFreeSpace(_KolibriFreeSpace); + _KolibriMemBlock = MemoryHeap::CreateBlock(begin, end, _KolibriFreeSpace); + unsigned int use_beg = (unsigned int)MemoryHeap::BlockBegin(_KolibriMemBlock) + + MemoryHeap::BlockAddSize - MemoryHeap::BlockEndSize; + unsigned int use_size = (unsigned int)use_end; + if (use_size <= use_beg) return 0; + else use_size -= use_beg; + return MemoryHeap::Alloc(_KolibriFreeSpace, use_size); + } + + bool _SetUseMemory(unsigned int use_mem); + + int _RecalculateUseMemory(unsigned int use_mem); + + void *Alloc(unsigned int size) + { + if (!size) return 0; + Lock(&_MemHeapMutex); + void *res = MemoryHeap::Alloc(_KolibriFreeSpace, size); + if (!res) + { + unsigned use_mem = (unsigned int)MemoryHeap::BlockEndFor(_KolibriMemBlock, size); + if (_SetUseMemory(_RecalculateUseMemory(use_mem))) + { + res = MemoryHeap::Alloc(_KolibriFreeSpace, size); + } + } + UnLock(&_MemHeapMutex); + return res; + } + + void *ReAlloc(void *mem, unsigned int size) + { + Lock(&_MemHeapMutex); + void *res = MemoryHeap::ReAlloc(_KolibriFreeSpace, mem, size); + if (!res && size) + { + unsigned use_mem = (unsigned int)MemoryHeap::BlockEndFor(_KolibriMemBlock, size); + if (_SetUseMemory(_RecalculateUseMemory(use_mem))) + { + res = MemoryHeap::ReAlloc(_KolibriFreeSpace, mem, size); + } + } + UnLock(&_MemHeapMutex); + return res; + } + + void Free(void *mem) + { + Lock(&_MemHeapMutex); + MemoryHeap::Free(_KolibriFreeSpace, mem); + UnLock(&_MemHeapMutex); + } + + void _FreeAndThreadFinish(void *mem, int *exit_proc_now); +} + +#endif // def __KOLIBRI__ + +#endif // ndef __KOLIBRI_HEAP_H_INCLUDED_ diff --git a/programs/bcc32/include/kos_heap.inc b/programs/bcc32/include/kos_heap.inc new file mode 100644 index 0000000000..89da5250b3 --- /dev/null +++ b/programs/bcc32/include/kos_heap.inc @@ -0,0 +1,97 @@ +;/*** + +KolibriHeapInit = @@Kolibri@_HeapInit$qpvt1t1 + +KolibriHeapAlloc = @@Kolibri@Alloc$qui + +KolibriHeapReAlloc = @@Kolibri@ReAlloc$qpvui + +KolibriHeapFree = @@Kolibri@Free$qpv + +KolibriHeapFreeAndThreadFinish = @Kolibri@_FreeAndThreadFinish$qpvpi + +proc @Kolibri@_SetUseMemory$qui + push ebx + mov eax,64 + mov ebx,1 + mov ecx,[esp+8] + int 0x40 + pop ebx + test eax,eax + jnz .set_use_memory_nomem + push ecx + push dword [@Kolibri@_KolibriMemBlock] + call @@MemoryHeap@ResizeBlock$q20MemoryHeap@TMemBlockpv + add esp,8 + mov al,1 + ret +.set_use_memory_nomem: + xor al,al + ret +endp + +proc @Kolibri@_RecalculateUseMemory$qui + mov eax,dword [esp+4] + mov ecx,(U_END + 3) and not 3 + cmp eax,ecx + jna .recalculate_use_memory_min + push ebx + sub eax,ecx + mov ebx,6 + mul ebx + dec ebx + div ebx + add eax,((U_END + 3) and not 3) + 3 + and eax,not 3 + pop ebx + ret +.recalculate_use_memory_min: + mov eax,ecx + ret +endp + +proc @Kolibri@_FreeAndThreadFinish$qpvpi + mov ebx,1 + mov ecx,[esp+8] + jmp .heap_free_tf_wait +.heap_free_tf_wait_loop: + mov eax,5 + int 0x40 + shl ebx,1 + cmp ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT + jna .heap_free_tf_wait + mov ebx,KOLIBRI_MUTEX_MAX_TIME_WAIT +.heap_free_tf_wait: + cmp dword [ecx],0 + jnz @Kolibri@ExitProcess$qv + lock bts dword [@Kolibri@_MemHeapMutex],0 + jc .heap_free_tf_wait_loop + push dword [esp+4] + push @Kolibri@_KolibriFreeSpace + call @@MemoryHeap@Free$qr21MemoryHeap@TFreeSpacepv + add esp,8 + mov byte [@Kolibri@_MemHeapMutex],0x40 + or eax,-1 + int 0x40 +endp + +macro call func +{ + if func eq @MemoryHeap@_FirstNotZeroBit$qui + bsf eax,[esp] + else if func eq @MemoryHeap@_CopyMemItemArray$quiuiui + xchg edi,[esp] + xchg esi,[esp+4] + mov ecx,[esp+8] + cld + sub ecx,esi + shr ecx,2 + rep movs dword [edi],[esi] + xchg edi,[esp] + xchg esi,[esp+4] + else + call func + end if +} + +;/**/ diff --git a/programs/bcc32/include/kos_lib.h b/programs/bcc32/include/kos_lib.h new file mode 100644 index 0000000000..1911f6b975 --- /dev/null +++ b/programs/bcc32/include/kos_lib.h @@ -0,0 +1,16 @@ +#ifndef __KOLIBRI_LIB_H_INCLUDED_ +#define __KOLIBRI_LIB_H_INCLUDED_ + +// Kolibri interface. + +namespace Kolibri // All kolibri functions, types and data are nested in the (Kolibri) namespace. +{ + unsigned int StrLen(const char *str); + char *StrCopy(char *dest, const char *src); + void *MemCopy(void *dest, const void *src, unsigned int n); + void *MemSet(void *s, char c, unsigned int n); + + double Floor(double x); +} + +#endif // __KOLIBRI_LIB_H_INCLUDED_ diff --git a/programs/bcc32/include/kos_lib.inc b/programs/bcc32/include/kos_lib.inc new file mode 100644 index 0000000000..819d94ff6d --- /dev/null +++ b/programs/bcc32/include/kos_lib.inc @@ -0,0 +1,106 @@ +proc @Kolibri@StrLen$qpxc uses edi + cld + mov edi,[esp+8] + mov ecx,-1 + xor al,al + repnz scas byte [edi] + not ecx + lea eax,[ecx-1] + ret +endp + +proc @Kolibri@StrCopy$qpcpxc uses esi edi + cld + mov edi,[esp+16] + mov ecx,-1 + mov esi,edi + xor al,al + repnz scas byte [edi] + not ecx + mov edi,[esp+12] + mov edx,ecx + mov eax,edi + shr ecx,2 + rep movs dword [edi],[esi] + mov ecx,edx + and ecx,3 + rep movs byte [edi],[esi] + ret +endp + +proc @Kolibri@MemCopy$qpvpxvui uses esi edi + cld + mov edi,[esp+12] + mov eax,edi + mov ecx,[esp+20] + mov esi,[esp+16] + mov edx,ecx + shr ecx,2 + rep movs dword [edi],[esi] + mov ecx,edx + and ecx,3 + rep movs byte [edi],[esi] + ret +endp + +proc @Kolibri@MemSet$qpvcui uses edi + cld + mov edi,[esp+8] + mov al,[esp+12] + mov ah,al + mov dx,ax + shl eax,16 + mov ax,dx + mov ecx,[esp+16] + mov edx,ecx + shr ecx,2 + rep stos dword [edi] + mov ecx,edx + and ecx,3 + rep stos byte [edi] + mov eax,[esp+4] + ret +endp + +proc __ftol + sub esp,12 + wait + fstcw word [esp+8] + wait + mov al,[esp+9] + or byte [esp+9],0x0c + fldcw word [esp+8] + fistp qword [esp] + mov [esp+9],al + fldcw word [esp+8] + mov eax,[esp] + mov edx,[esp+4] + add esp,12 + ret +endp + +proc @Kolibri@Floor$qd + fld qword [esp+4] + mov ax,[esp+10] + shl ax,1 + cmp ax,0x8680 + ja .floor_end + mov ch,4 + sub esp,2 + wait + fstcw word [esp] + mov ax,0xf3ff + wait + mov dx,[esp] + and ax,dx + or ah,ch + mov [esp],ax + fldcw word [esp] + frndint + mov [esp],dx + fldcw word [esp] + add esp,2 +.floor_end: + ret +endp + diff --git a/programs/bcc32/include/kos_start.inc b/programs/bcc32/include/kos_start.inc new file mode 100644 index 0000000000..57b3905dc7 --- /dev/null +++ b/programs/bcc32/include/kos_start.inc @@ -0,0 +1,85 @@ +use32 +org 0 + db 'MENUET01' + dd 1 + dd @Kolibri@Main$qv + dd I_END + dd U_END+STACKSIZE+HEAPSIZE + dd U_END+STACKSIZE + dd @Kolibri@CommandLine,0 + +ptr equ +offset equ +short equ +tbyte equ tword + +PTR equ +OFFSET equ +SHORT equ +TBYTE equ TWORD + +macro movsb a,b +{ + if a eq & b eq + movsb + else + movsx a,b + end if +} + +macro movsw a,b +{ + if a eq & b eq + movsw + else + movsx a,b + end if +} + +macro segment name {} + +macro endseg name {} + +macro usedef [link] +{ + common + if ~link eq + virtual at 0 + forward + dd link + common + end virtual + end if +} + +macro define_f x,[link] +{ + common + if x eq + else if used x + x: + usedef link +} + +macro enddef [link] +{ + common + usedef link + end if +} + +macro newdef x,[link] +{ + common + end if + if x eq + else if used x + x: + usedef link +} + +macro nextdef x +{ +x: +} + diff --git a/programs/bcc32/include/memheap.h b/programs/bcc32/include/memheap.h new file mode 100644 index 0000000000..bf8aa101fc --- /dev/null +++ b/programs/bcc32/include/memheap.h @@ -0,0 +1,626 @@ +#ifndef __MEMORY_HEAP_RBTREE_H_INCLUDED_ +#define __MEMORY_HEAP_RBTREE_H_INCLUDED_ + +namespace MemoryHeap +{ + typedef unsigned int TMemItem; + + enum {NumTreeSmall = 8 * sizeof(TMemItem)}; + +// Memory heap interface. + + struct TFreeSpace + { + TMemItem Small[NumTreeSmall], Min, SmallMask; + }; + + struct TMemBlock + { + TMemItem *Begin; + }; + + bool BlockValid(const TMemBlock &block); // Is the given memory block valid? + void *BlockBegin(const TMemBlock &block); // Return the beginning address of the block. + void *BlockEnd(const TMemBlock &block); // Return the ending address of the block. + TFreeSpace &BlockFreeSpace(const TMemBlock &block); // Return the free space of the block. + + void InitFreeSpace(TFreeSpace &fs); // Initialize the free space. + TMemBlock NullBlock(); // Return null invalid block. + TMemBlock CreateBlock(void *begin, void *end, TFreeSpace &fs); + // Create a memory block with the given begin and end and add free space of it to (fs), + //_ give (BlockAddSize) bytes of the block for it's data. + //_ (Program can alloc (end - begin - BlockAddSize) bytes after it, + //_ that must be not less than (MemMinSize) ). + TMemBlock CreateBlock(void *begin, void *end); + // Create a memory block with the given begin and end and new free space for it, + //_ give (BlockAddSizeFS) bytes of the block for it's data. + //_ (Program can alloc (end - begin - BlockAddSizeFS) bytes after it, + //_ that must be not less than (MemMinSize) ). + void ResizeBlock(TMemBlock block, void *new_end); // Resize the memory block to the given new end. + void RemoveBlock(TMemBlock block); // Remove the given memory block. + + void *BlockEndFor(TMemBlock block, unsigned int size); + // Return the new end of the block needed for (ResizeBlock) to alloc the given size of memory. + unsigned int BlockSize(TMemBlock block); // Return the size of the given block. + unsigned int MemSize(void *mem); // Return the size of the allocced memory. + + void *Alloc(TFreeSpace &fs, unsigned int size); + // Alloc a memory in the given free space, give (MemAddSize) bytes for it's data. + void *ReAlloc(TFreeSpace &fs, unsigned int size, void *mem); + // ReAlloc the given memory, it must lie in the block with the given free space. + void Free(TFreeSpace &fs, void *mem); + // Free the given memory, it must lie in the block with the given free space. + +// Macro definitions. + +#define MEMORY_HEAP_ALIGN_DOWN(s) (MemoryHeap::TMemItem(s) & ~(MemoryHeap::MemAlign - 1)) +#define MEMORY_HEAP_ALIGN_UP(s) ((MemoryHeap::TMemItem(s) + (MemoryHeap::MemAlign - 1)) & ~(MemoryHeap::MemAlign - 1)) +#define MEMORY_HEAP_ITEM(s,k) ( ((MemoryHeap::TMemItem*)(s))[(k)] ) +#define MEMORY_HEAP_NEXT(s) (MEMORY_HEAP_ITEM((s),-1)) +#define MEMORY_HEAP_PREV(s) (MEMORY_HEAP_ITEM((s),-2)) +#define MEMORY_HEAP_FREE(s) (MEMORY_HEAP_ITEM((s),-1) & 1) + +// Constants. + + enum {MemAlign = sizeof(TMemItem)}; + enum {MemAddSize = MEMORY_HEAP_ALIGN_UP(2 * sizeof(TMemItem))}; + enum {BlockEndSize = MemAddSize}; + enum {BlockAddSize = MEMORY_HEAP_ALIGN_UP(4 * sizeof(TMemItem)) + BlockEndSize}; + enum {BlockAddSizeFS = BlockAddSize + BlockEndSize + MEMORY_HEAP_ALIGN_UP(sizeof(TFreeSpace))}; + enum {MemMinSize = MEMORY_HEAP_ALIGN_UP(2 * sizeof(TMemItem))}; + +// Inline functions. + + inline bool BlockValid(const TMemBlock &block) {return block.Begin != 0;} + + inline void *BlockBegin(const TMemBlock &block) {return (void*)block.Begin;} + + inline void *BlockEnd(const TMemBlock &block) {return block.Begin ? (void*)block.Begin[1] : 0;} + + inline TFreeSpace &BlockFreeSpace(const TMemBlock &block) {return *(TFreeSpace*)block.Begin[0];} + + inline TMemBlock NullBlock() {TMemBlock block; block.Begin = 0; return block;} + + inline void *BlockEndFor(TMemBlock block, unsigned int size) + { + TMemItem last = (TMemItem)block.Begin[1]; + TMemItem prevlast = MEMORY_HEAP_PREV(last); + return (void*)( (MEMORY_HEAP_FREE(prevlast) ? prevlast : last) + MemAddSize + + ((size <= MemMinSize) ? MemMinSize : MEMORY_HEAP_ALIGN_UP(size)) ); + } + + inline unsigned int BlockSize(TMemBlock block) + { + if (!block.Begin) return 0; + return (unsigned int)(block.Begin[1] - (TMemItem)block.Begin); + } + + inline unsigned int MemSize(void *mem) + { + if (!mem) return 0; + TMemItem c = (TMemItem)mem; + return MEMORY_HEAP_NEXT(c) - c - MemAddSize; + } + +// Free space item functions. + + TMemItem _FirstNotZeroBit(TMemItem i) + { + TMemItem r = 0; + while ((i >>= 1) != 0) r++; + return r; + } + + void _RBTreeRotate(TMemItem parent, TMemItem item, int side) + { + TMemItem temp = MEMORY_HEAP_ITEM(parent,0); + MEMORY_HEAP_ITEM(item,0) = temp; + if (temp) + { + if (MEMORY_HEAP_ITEM(temp,2) == parent) + { + MEMORY_HEAP_ITEM(temp,2) = item; + } + else MEMORY_HEAP_ITEM(temp,3) = item; + } + temp = MEMORY_HEAP_ITEM(item,side^1); + if (temp) MEMORY_HEAP_ITEM(temp,0) = parent; + MEMORY_HEAP_ITEM(parent,side) = temp; + MEMORY_HEAP_ITEM(parent,0) = item; + MEMORY_HEAP_ITEM(item,side^1) = parent; + temp = MEMORY_HEAP_ITEM(parent,1); + MEMORY_HEAP_ITEM(parent,1) = MEMORY_HEAP_ITEM(item,1); + MEMORY_HEAP_ITEM(item,1) = temp; + } + + void InitFreeSpace(TFreeSpace &fs) + { + TMemItem i; + for (i = 0; i <= NumTreeSmall; i++) fs.Small[i] = 0; + fs.Min = 0; fs.SmallMask = 0; + } + + void _FreeAdd(TFreeSpace &fs, TMemItem item) + { + TMemItem size = MEMORY_HEAP_NEXT(item) - item; + if (size < MemAddSize + MemMinSize + MemAlign * NumTreeSmall) + { + TMemItem s = (size - (MemAddSize + MemMinSize)) / MemAlign; + TMemItem &addto = fs.Small[s]; + MEMORY_HEAP_ITEM(item,1) = (TMemItem)(&addto); + MEMORY_HEAP_ITEM(item,0) = (TMemItem)addto; + if (addto) MEMORY_HEAP_ITEM(addto,1) = item; + addto = item; + fs.SmallMask |= TMemItem(1) << s; + return; + } + TMemItem addto = fs.Min, parent, temp; + MEMORY_HEAP_ITEM(item,2) = 0; + MEMORY_HEAP_ITEM(item,3) = 0; + if (!addto) + { + MEMORY_HEAP_ITEM(item,0) = 0; + MEMORY_HEAP_ITEM(item,1) = 1; + fs.Min = item; + return; + } + MEMORY_HEAP_ITEM(item,1) = 0; + TMemItem side = 2; + if (MEMORY_HEAP_NEXT(addto) - addto >= size) fs.Min = item; + else + { + for (;;) + { + parent = MEMORY_HEAP_ITEM(addto,0); + if (!parent) break; + if (MEMORY_HEAP_NEXT(parent) - parent < size) addto = parent; + else break; + } + for (;;) + { + if (MEMORY_HEAP_NEXT(addto) - addto < size) + { + temp = MEMORY_HEAP_ITEM(addto,3); + if (!temp) {side = 3; break;} + addto = temp; + } + else + { + temp = MEMORY_HEAP_ITEM(addto,2); + if (!temp) break; + addto = temp; + } + } + } + MEMORY_HEAP_ITEM(item,0) = addto; + MEMORY_HEAP_ITEM(addto,side) = item; + for (;;) + { + if (MEMORY_HEAP_ITEM(addto,1) != 0) return; + parent = MEMORY_HEAP_ITEM(addto,0); + temp = MEMORY_HEAP_ITEM(parent,2); + if (temp == addto) + { + temp = MEMORY_HEAP_ITEM(parent,3); + side = 2; + } + else side = 3; + if (!temp || MEMORY_HEAP_ITEM(temp,1) != 0) break; + MEMORY_HEAP_ITEM(addto,1) = 1; + MEMORY_HEAP_ITEM(temp,1) = 1; + item = parent; + addto = MEMORY_HEAP_ITEM(item,0); + if (!addto) return; + MEMORY_HEAP_ITEM(item,1) = 0; + } + if (MEMORY_HEAP_ITEM(addto,side) != item) + { + temp = MEMORY_HEAP_ITEM(item,side); + if (temp) MEMORY_HEAP_ITEM(temp,0) = addto; + MEMORY_HEAP_ITEM(addto,side^1) = temp; + MEMORY_HEAP_ITEM(addto,0) = item; + MEMORY_HEAP_ITEM(item,side) = addto; + MEMORY_HEAP_ITEM(item,0) = parent; + MEMORY_HEAP_ITEM(parent,side) = item; + } + else item = addto; + _RBTreeRotate(parent, item, side); + } + + void _FreeDel(TFreeSpace &fs, TMemItem item) + { + TMemItem size = MEMORY_HEAP_NEXT(item) - item; + if (size < MemAddSize + MemMinSize + MemAlign * NumTreeSmall) + { + TMemItem prev = MEMORY_HEAP_ITEM(item,1); + TMemItem next = MEMORY_HEAP_ITEM(item,0); + MEMORY_HEAP_ITEM(prev,0) = next; + if (next) MEMORY_HEAP_ITEM(next,1) = prev; + else + { + TMemItem s = (size - (MemAddSize + MemMinSize)) / MemAlign; + if (!fs.Small[s]) fs.SmallMask &= ~(TMemItem(1) << s); + } + return; + } + TMemItem parent, temp, second, add; + TMemItem side = 2; + temp = MEMORY_HEAP_ITEM(item,3); + if (temp) + { + for (;;) + { + second = temp; + temp = MEMORY_HEAP_ITEM(temp,2); + if (!temp) break; + } + if (fs.Min == item) fs.Min = second; + add = MEMORY_HEAP_ITEM(second,3); + parent = MEMORY_HEAP_ITEM(second,0); + if (parent == item) {parent = second; side = 3;} + else + { + temp = MEMORY_HEAP_ITEM(item,3); + MEMORY_HEAP_ITEM(second,3) = temp; + MEMORY_HEAP_ITEM(temp,0) = second; + } + temp = MEMORY_HEAP_ITEM(item,2); + MEMORY_HEAP_ITEM(second,2) = temp; + if (temp) MEMORY_HEAP_ITEM(temp,0) = second; + temp = MEMORY_HEAP_ITEM(item,0); + MEMORY_HEAP_ITEM(second,0) = temp; + if (temp) + { + if (MEMORY_HEAP_ITEM(temp,2) == item) + { + MEMORY_HEAP_ITEM(temp,2) = second; + } + else MEMORY_HEAP_ITEM(temp,3) = second; + } + MEMORY_HEAP_ITEM(parent,side) = add; + if (add) MEMORY_HEAP_ITEM(add,0) = parent; + bool color = MEMORY_HEAP_ITEM(second,1); + MEMORY_HEAP_ITEM(second,1) = MEMORY_HEAP_ITEM(item,1); + if (!color) return; + } + else + { + if (fs.Min == item) fs.Min = MEMORY_HEAP_ITEM(item,0); + add = MEMORY_HEAP_ITEM(item,2); + parent = MEMORY_HEAP_ITEM(item,0); + if (add) MEMORY_HEAP_ITEM(add,0) = parent; + if (parent) + { + if (MEMORY_HEAP_ITEM(parent,2) == item) + { + MEMORY_HEAP_ITEM(parent,2) = add; + } + else + { + MEMORY_HEAP_ITEM(parent,3) = add; + side = 3; + } + } + else + { + if (add) MEMORY_HEAP_ITEM(add,1) = 1; + return; + } + if (!MEMORY_HEAP_ITEM(item,1)) return; + } + if (add && !MEMORY_HEAP_ITEM(add,1)) + { + MEMORY_HEAP_ITEM(add,1) = 1; + return; + } + for (;;) + { + second = MEMORY_HEAP_ITEM(parent,side^1); + if (!MEMORY_HEAP_ITEM(second,1)) + { + _RBTreeRotate(parent, second, side^1); + second = MEMORY_HEAP_ITEM(parent,side^1); + } + temp = MEMORY_HEAP_ITEM(second,side^1); + if (temp && !MEMORY_HEAP_ITEM(temp,1)) + { + MEMORY_HEAP_ITEM(temp,1) = 1; + break; + } + temp = MEMORY_HEAP_ITEM(second,side); + if (temp && !MEMORY_HEAP_ITEM(temp,1)) + { + _RBTreeRotate(second, temp, side); + MEMORY_HEAP_ITEM(second,1) = 1; + second = temp; + break; + } + MEMORY_HEAP_ITEM(second,1) = 0; + if (!MEMORY_HEAP_ITEM(parent,1)) + { + MEMORY_HEAP_ITEM(parent,1) = 1; + return; + } + second = parent; + parent = MEMORY_HEAP_ITEM(second,0); + if (!parent) return; + if (MEMORY_HEAP_ITEM(parent,2) == second) side = 2; + else side = 3; + } + _RBTreeRotate(parent, second, side^1); + } + + TMemItem _FreeFindAfter(TMemItem item, TMemItem size) + { + if (!item) return 0; + TMemItem paritem, s; + if (MEMORY_HEAP_NEXT(item) - item >= size) return item; + for (;;) + { + paritem = MEMORY_HEAP_ITEM(item,0); + if (!paritem) break; + s = MEMORY_HEAP_NEXT(paritem) - paritem; + if (s == size) return paritem; + if (s < size) item = paritem; + else break; + } + MEMORY_HEAP_ITEM(item,3); + for (;;) + { + if (!item) return paritem; + s = MEMORY_HEAP_NEXT(item) - item; + if (s == size) return item; + if (s < size) item = MEMORY_HEAP_ITEM(item,3); + else + { + paritem = item; + item = MEMORY_HEAP_ITEM(item,2); + } + } + } + + TMemItem _FreeFind(TFreeSpace &fs, TMemItem size) + { + TMemItem item, nextitem, s; + if (size < MemAddSize + MemMinSize + MemAlign * NumTreeSmall) + { + TMemItem m, t; + s = (size - (MemAddSize + MemMinSize)) / MemAlign; + item = fs.Small[s]; + if (item) return item; + if (size < MemAlign * NumTreeSmall) + { + t = size / MemAlign; + m = fs.SmallMask >> t; + if (m) return fs.Small[t + _FirstNotZeroBit(m)]; + else if (fs.Min) return fs.Min; + } + else + { + item = _FreeFindAfter(fs.Min, size + 1 + MemAddSize + MemMinSize); + if (item) return item; + } + m = fs.SmallMask >> s; + if (m) return fs.Small[s + _FirstNotZeroBit(m)]; + else return fs.Min; + } + item = _FreeFindAfter(fs.Min, ++size); + if (!item) return 0; + s = MEMORY_HEAP_NEXT(item) - item; + if (s == size) return item; + size += MemAddSize + MemMinSize; + if (s >= size) return item; + nextitem = _FreeFindAfter(item, size); + return nextitem ? nextitem : item; + } + +// Block functions. + + inline void _CreateBlockEnd(TMemBlock &block, TFreeSpace &fs, TMemItem c, TMemItem e) + { + block.Begin[0] = (TMemItem)(&fs); + if (e - c < TMemItem(MemAddSize + MemMinSize)) + { + MEMORY_HEAP_NEXT(c) = 0; + block.Begin[1] = c; + } + else + { + MEMORY_HEAP_NEXT(c) = e + 1; + _FreeAdd(fs, c); + MEMORY_HEAP_PREV(e) = c; + MEMORY_HEAP_NEXT(e) = 0; + block.Begin[1] = e; + } + } + + TMemBlock CreateBlock(void *begin, void *end, TFreeSpace &fs) + { + TMemBlock block = {0}; + TMemItem b = MEMORY_HEAP_ALIGN_UP(begin); + TMemItem e = MEMORY_HEAP_ALIGN_DOWN(end); + if (e <= b || e - b < TMemItem(BlockAddSize - MemAddSize)) return block; + block.Begin = (TMemItem*)b; + b += MEMORY_HEAP_ALIGN_UP(4 * sizeof(TMemItem)); + MEMORY_HEAP_PREV(b) = 0; + _CreateBlockEnd(block, fs, b, e); + return block; + } + + TMemBlock CreateBlock(void *begin, void *end) + { + TMemBlock block = {0}; + TMemItem b = MEMORY_HEAP_ALIGN_UP(begin); + TMemItem e = MEMORY_HEAP_ALIGN_DOWN(end); + if (e <= b || e - b < TMemItem(BlockAddSizeFS - MemAddSize)) return block; + block.Begin = (TMemItem*)b; + b += MEMORY_HEAP_ALIGN_UP(4 * sizeof(TMemItem)); + TMemItem c = b + MemAddSize + MEMORY_HEAP_ALIGN_UP(sizeof(TFreeSpace)); + MEMORY_HEAP_PREV(b) = 0; + MEMORY_HEAP_NEXT(b) = c; + MEMORY_HEAP_PREV(c) = b; + InitFreeSpace(*(TFreeSpace*)b); + _CreateBlockEnd(block, *(TFreeSpace*)b, c, e); + return block; + } + + void ResizeBlock(TMemBlock block, void *new_end) + { + if (!BlockValid(block)) return; + TMemItem e = MEMORY_HEAP_ALIGN_DOWN(new_end); + TMemItem c = block.Begin[1]; + TFreeSpace &fs = *(TFreeSpace*)block.Begin[0]; + do + { + if (c == e) return; + else if (c > e) + { + while ((c = MEMORY_HEAP_PREV(c)) > e) + { + if (MEMORY_HEAP_FREE(c)) _FreeDel(fs, c); + } + if (!c) {block.Begin = 0; return;} + if (MEMORY_HEAP_FREE(c)) + { + _FreeDel(fs, c); + if (e - c < TMemItem(MemAddSize + MemMinSize)) e = c; + else + { + MEMORY_HEAP_NEXT(c) = e + 1; + _FreeAdd(*(TFreeSpace*)block.Begin[0], c); + break; + } + } + else if (e - c >= TMemItem(MemAddSize + MemMinSize)) + { + MEMORY_HEAP_NEXT(c) = e; break; + } + MEMORY_HEAP_NEXT(c) = 0; + block.Begin[1] = c; + if (c == e) return; + } + TMemItem pc = MEMORY_HEAP_PREV(c); + if (pc && MEMORY_HEAP_FREE(pc)) _FreeDel(fs, c = pc); + else if (e - c < TMemItem(MemAddSize + MemMinSize)) return; + MEMORY_HEAP_NEXT(c) = e + 1; + _FreeAdd(fs, c); + } while(false); + MEMORY_HEAP_PREV(e) = c; + MEMORY_HEAP_NEXT(e) = 0; + block.Begin[1] = e; + } + + void RemoveBlock(TMemBlock block) + { + if (!BlockValid(block)) return; + TMemItem e = block.Begin[1]; + TFreeSpace &fs = *(TFreeSpace*)block.Begin[0]; + while ((e = MEMORY_HEAP_PREV(e)) != 0) + { + if (MEMORY_HEAP_FREE(e)) _FreeDel(fs, e); + } + block.Begin = 0; + } + +// Free space functions. + + void _CopyMemItemArray(TMemItem dest, TMemItem src, TMemItem end) + { + TMemItem k = (end - src) / sizeof(TMemItem); + TMemItem *d = (TMemItem*)dest; + TMemItem *s = (TMemItem*)src; + while (k--) *(d++) = *(s++); + } + + void *Alloc(TFreeSpace &fs, unsigned int size) + { + if (!size) return 0; + TMemItem s = MEMORY_HEAP_ALIGN_UP(size) + MemAddSize; + if (s < MemAddSize + MemMinSize) s = MemAddSize + MemMinSize; + TMemItem c = _FreeFind(fs, s); + if (!c) return 0; + _FreeDel(fs, c); + TMemItem nc = --MEMORY_HEAP_NEXT(c); + TMemItem mc = c + s; + if (nc - (MemAddSize + MemMinSize) >= mc) + { + MEMORY_HEAP_NEXT(c) = mc; + MEMORY_HEAP_PREV(mc) = c; + MEMORY_HEAP_NEXT(mc) = nc + 1; + MEMORY_HEAP_PREV(nc) = mc; + _FreeAdd(fs, mc); + } + return (void*)c; + } + + void *ReAlloc(TFreeSpace &fs, void *mem, unsigned int size) + { + if (!mem) return Alloc(fs, size); + if (!size) {Free(fs, mem); return 0;} + TMemItem s = MEMORY_HEAP_ALIGN_UP(size) + MemAddSize; + TMemItem c = (TMemItem)mem; + TMemItem mc = MEMORY_HEAP_NEXT(c); + TMemItem nc = MEMORY_HEAP_NEXT(mc); + if (--nc & 1) nc = mc; + if (s < MemAddSize + MemMinSize) s = MemAddSize + MemMinSize; + if (nc - c < s) + { + mem = Alloc(fs, size); + if (mem) + { + _CopyMemItemArray((TMemItem)mem, c, mc - MemAddSize); + Free(fs, (void*)c); + return mem; + } + else + { + TMemItem pc = MEMORY_HEAP_PREV(c); + if (pc && MEMORY_HEAP_FREE(pc) && nc - pc >= s) + { + _FreeDel(fs, pc); + _CopyMemItemArray(pc, c, mc - MemAddSize); + c = pc; + } + else return 0; + } + } + if (mc < nc) _FreeDel(fs, mc); + mc = c + s; + if (nc - (MemAddSize + MemMinSize) >= mc) + { + MEMORY_HEAP_NEXT(c) = mc; + MEMORY_HEAP_PREV(mc) = c; + MEMORY_HEAP_NEXT(mc) = nc + 1; + MEMORY_HEAP_PREV(nc) = mc; + _FreeAdd(fs, mc); + } + else + { + MEMORY_HEAP_NEXT(c) = nc; + MEMORY_HEAP_PREV(nc) = c; + } + return (void*)c; + } + + int free_a = 0; + + void Free(TFreeSpace &fs, void *mem) + { + TMemItem c = (TMemItem)mem; + if (!c) return; + TMemItem pc = MEMORY_HEAP_PREV(c); + TMemItem mc = MEMORY_HEAP_NEXT(c); + TMemItem nc = MEMORY_HEAP_NEXT(mc); + if (--nc & 1) nc = mc; + else _FreeDel(fs, mc); + if (free_a == 1) return; + if (pc && MEMORY_HEAP_FREE(pc)) _FreeDel(fs, c = pc); + MEMORY_HEAP_NEXT(c) = nc + 1; + MEMORY_HEAP_PREV(nc) = c; + if (free_a == 2) return; + _FreeAdd(fs, c); + } +} + +#endif // ndef __MEMORY_HEAP_RBTREE_H_INCLUDED_ + diff --git a/programs/bcc32/kos32-bcc/compile.txt b/programs/bcc32/kos32-bcc/compile.txt new file mode 100644 index 0000000000..baefd5eba8 --- /dev/null +++ b/programs/bcc32/kos32-bcc/compile.txt @@ -0,0 +1,8 @@ +В файле kos32-bcc.asm находится патч для компилятора Borland C++ 5.5.1. +После применения данного патча компилятор в режиме компиляции с опцией '-S' +выдает *.asm файлы с синтаксисом более похожим на ассемблер fasm. + +Применение: +fasm kos32-bcc.asm kos32-bcc.exe + +bcc32.exe должен лежать рядом с kos32-bcc.asm diff --git a/programs/bcc32/kos32-bcc/kos32-bcc.asm b/programs/bcc32/kos32-bcc/kos32-bcc.asm new file mode 100644 index 0000000000..313bfdf384 --- /dev/null +++ b/programs/bcc32/kos32-bcc/kos32-bcc.asm @@ -0,0 +1,27 @@ +; patch for new fasm +use32 + +file 'bcc32.exe':0,0x4a8f +dd 0x90909090,0x90909090 ;fix end proc +db 0xb8 +dd 0x4a626b + +file 'bcc32.exe':0x4a9c,0x5753-0x4a9c +dd 0x4b2472 ;fix label byte +file 'bcc32.exe':0x5757,0x575a-0x5757 +dd 0x4b2472 ;fix proc near +file 'bcc32.exe':0x575e,0x5761-0x575e +dd 0x4b2472 ;fix label word +file 'bcc32.exe':0x5765,0x5768-0x5765 +dd 0x4b2472 ;fix label dword +file 'bcc32.exe':0x576c,0x576f-0x576c +dd 0x4b2472 ;fix label qword +file 'bcc32.exe':0x5773,0x5776-0x5773 +dd 0x4b2472 ;fix label tbyte + +file 'bcc32.exe':0x577a,0x56216-0x577a +db '_' ;fix '$' to '_' +file 'bcc32.exe':0x56217,0xd4400-0x56217 + +;0x4b2472 - ':',13,10,0 +;0x4a626b - 13,10,0