DJGPP backend working.
This commit is contained in:
parent
ef63b14c2f
commit
4d0b209adc
16 changed files with 1451 additions and 840 deletions
|
@ -23,6 +23,8 @@ HEADERS += \
|
|||
$$SHARED/stddclmr.h \
|
||||
$$SHARED/thirdparty/memwatch/memwatch.h \
|
||||
$$SHARED/thirdparty/stb_ds.h \
|
||||
$$SHARED/log.h \
|
||||
$$SHARED/util.h \
|
||||
src/gui/font.h \
|
||||
src/gui/gui.h \
|
||||
src/gui/image.h \
|
||||
|
@ -38,6 +40,8 @@ SOURCES += \
|
|||
$$SHARED/array.c \
|
||||
$$SHARED/memory.c \
|
||||
$$SHARED/thirdparty/memwatch/memwatch.c \
|
||||
$$SHARED/log.c \
|
||||
$$SHARED/util.c \
|
||||
src/gui/font.c \
|
||||
src/gui/gui.c \
|
||||
src/gui/image.c \
|
||||
|
|
|
@ -25,7 +25,7 @@ static ColorT _mouseTransparency;
|
|||
|
||||
|
||||
void guiRun(void) {
|
||||
EventT event;
|
||||
EventT event = { 0 };
|
||||
|
||||
while (_guiRunning) {
|
||||
// Read mouse & keyboard.
|
||||
|
@ -75,14 +75,15 @@ void guiShutdown(void) {
|
|||
}
|
||||
|
||||
|
||||
void guiStartup(int16_t width, int16_t height, int16_t depth) {
|
||||
uint8_t guiStartup(int16_t width, int16_t height, int16_t depth) {
|
||||
|
||||
platformStartup(width, height, depth);
|
||||
if (platformStartup(width, height, depth) == FAIL) return FAIL;
|
||||
|
||||
__guiScreenBuffer = videoSurfaceScreenGet();
|
||||
__guiBackBuffer = videoSurfaceCreate(videoDisplayWidthGet(), videoDisplayHeightGet());
|
||||
videoSurfaceSet(__guiBackBuffer);
|
||||
|
||||
_mousePointer = imageLoad("mouse.png");
|
||||
_mousePointer = imageLoad("mouse.png");
|
||||
_mouseTransparency = videoSurfacePixelGet(_mousePointer, videoSurfaceWidthGet(_mousePointer) - 2, 0); // Find our transparency color.
|
||||
|
||||
__guiFontVGA8x14 = fontLoad("vga8x14.dat");
|
||||
|
@ -90,6 +91,8 @@ void guiStartup(int16_t width, int16_t height, int16_t depth) {
|
|||
wmStartup();
|
||||
|
||||
guiRegister(windowRegister);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -70,13 +70,13 @@ extern FontT *__guiFontVGA8x14;
|
|||
#define GUI_WHITE __guiBaseColors[15]
|
||||
|
||||
|
||||
void guiModesShow(void);
|
||||
void guiRegister(WidgetRegisterT widgetRegister);
|
||||
void guiRun(void);
|
||||
void guiShutdown(void);
|
||||
void guiStartup(int16_t width, int16_t height, int16_t depth);
|
||||
void guiStop(void);
|
||||
void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void guiModesShow(void);
|
||||
void guiRegister(WidgetRegisterT widgetRegister);
|
||||
void guiRun(void);
|
||||
void guiShutdown(void);
|
||||
uint8_t guiStartup(int16_t width, int16_t height, int16_t depth);
|
||||
void guiStop(void);
|
||||
void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
|
||||
|
||||
#endif // GUI_H
|
||||
|
|
|
@ -7,19 +7,22 @@ int main(int argc, char *argv[]) {
|
|||
uint16_t i;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
guiStartup(800, 600, 24);
|
||||
memoryStartup(argv[0]);
|
||||
logOpenByHandle(memoryLogHandleGet());
|
||||
|
||||
i = 1;
|
||||
//for (i=1; i<4; i++) {
|
||||
sprintf(title, "Testing %d", i);
|
||||
windowCreate(i * 50, i * 50, 300, 200, title, WIN_CLOSE | WIN_MAXIMIZE | WIN_MINIMIZE | WIN_RESIZE);
|
||||
//}
|
||||
if (guiStartup(800, 600, 32) == SUCCESS) {
|
||||
i = 1;
|
||||
//for (i=1; i<4; i++) {
|
||||
sprintf(title, "Testing %d", i);
|
||||
windowCreate(i * 50, i * 50, 300, 200, title, WIN_CLOSE | WIN_MAXIMIZE | WIN_MINIMIZE | WIN_RESIZE);
|
||||
//}
|
||||
guiRun();
|
||||
guiShutdown();
|
||||
}
|
||||
|
||||
guiRun();
|
||||
|
||||
guiShutdown();
|
||||
logClose();
|
||||
memoryShutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,9 +7,14 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "stddclmr.h"
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifdef BACKEND_DJGPP
|
||||
|
||||
|
||||
#include "os.h"
|
||||
|
||||
#include <dos.h>
|
||||
#include <dpmi.h>
|
||||
#include <go32.h>
|
||||
|
@ -8,19 +10,52 @@
|
|||
#include <conio.h>
|
||||
#include <sys/farptr.h>
|
||||
#include <sys/nearptr.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "djgpp.h"
|
||||
|
||||
|
||||
#define DIVISIBLE_BY_EIGHT(x) ((((x) >> 3) << 3) == (x))
|
||||
|
||||
|
||||
// These are all we support
|
||||
#define VBE_MM_PACKED 4
|
||||
#define VBE_MM_DCOLOR 6
|
||||
|
||||
|
||||
// Based on http://www.brackeen.com/vga/source/djgpp20/mouse.c.html
|
||||
#define MOUSE_INT 0x33
|
||||
|
||||
#define MOUSE_RESET 0x00
|
||||
#define MOUSE_STATUS 0x03
|
||||
#define MOUSE_GETMOTION 0x0B
|
||||
|
||||
#define MOUSE_LEFT_BUTTON 0x01
|
||||
#define MOUSE_RIGHT_BUTTON 0x02
|
||||
#define MOUSE_MIDDLE_BUTTON 0x04
|
||||
|
||||
|
||||
#define KEYBOARD_READ_EXTENDED 0x10
|
||||
#define KEYBOARD_CHECK_EXTENDED 0x11
|
||||
#define KEYBOARD_META_EXTENDED 0x12
|
||||
|
||||
|
||||
enum MetaBitsE {
|
||||
KEY_META_SHIFT_RIGHT = 0,
|
||||
KEY_META_SHIFT_LEFT,
|
||||
KEY_META_CONTROL,
|
||||
KEY_META_ALT,
|
||||
KEY_META_SCROLL_LOCKED,
|
||||
KEY_META_NUM_LOCKED,
|
||||
KEY_META_CAPS_LOCKED,
|
||||
KEY_META_INSERT_LOCKED,
|
||||
KEY_META_CONTROL_LEFT,
|
||||
KEY_META_ALT_LEFT,
|
||||
KEY_META_CONTROL_RIGHT,
|
||||
KEY_META_ALT_RIGHT,
|
||||
KEY_META_SCROLL_LOCK,
|
||||
KEY_META_NUM_LOCK,
|
||||
KEY_META_CAPS_LOCK,
|
||||
KEY_META_SYSREQ
|
||||
};
|
||||
|
||||
|
||||
typedef struct VBEInfoS {
|
||||
char vbeSignature[4]; // 'VESA' 4 byte signature
|
||||
int16_t vbeVersion; // VBE version number
|
||||
|
@ -121,6 +156,9 @@ typedef struct VBESurfaceS {
|
|||
} VBESurfaceT;
|
||||
|
||||
|
||||
extern ColorT *__guiBaseColors;
|
||||
|
||||
|
||||
static VBESurfaceT _vbeSurface;
|
||||
static VBEInfoT _vbeInfo;
|
||||
static VBEModeInfoT _vbeModeInfo;
|
||||
|
@ -148,7 +186,98 @@ void (*videoSurfacePixelSet)(uint16_t x, uint16_t y, ColorT color);
|
|||
|
||||
|
||||
void platformEventGet(EventT *event) {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int16_t dx;
|
||||
int16_t dy;
|
||||
int16_t h = videoDisplayHeightGet();
|
||||
int16_t w = videoDisplayWidthGet();
|
||||
int16_t ext = bioskey(KEYBOARD_CHECK_EXTENDED);
|
||||
int16_t meta = bioskey(KEYBOARD_META_EXTENDED);
|
||||
int16_t key = 0;
|
||||
union REGS regs;
|
||||
|
||||
// Read mouse motion.
|
||||
regs.x.ax = MOUSE_GETMOTION;
|
||||
int86(MOUSE_INT, ®s, ®s);
|
||||
dx = regs.x.cx; // Temporary assignment changes values to signed.
|
||||
dy = regs.x.dx; // Don't skip this step. :-)
|
||||
x = event->x + dx;
|
||||
y = event->y + dy;
|
||||
if (x < 0) x = 0;
|
||||
if (x > w - 1) x = w - 1;
|
||||
if (y < 0) y = 0;
|
||||
if (y > h - 1) y = h - 1;
|
||||
event->x = x;
|
||||
event->y = y;
|
||||
|
||||
// Read mouse buttons.
|
||||
regs.x.ax = MOUSE_STATUS;
|
||||
int86(MOUSE_INT, ®s, ®s);
|
||||
|
||||
// Was the left button down?
|
||||
if (event->buttons & BUTTON_LEFT) {
|
||||
// Yes. Is it still down?
|
||||
if ((regs.x.bx & MOUSE_LEFT_BUTTON) > 0) {
|
||||
// Yes. Do nothing.
|
||||
} else {
|
||||
// No! Clear it and set UP event.
|
||||
event->buttons &= ~BUTTON_LEFT;
|
||||
event->flags |= EVENT_FLAG_LEFT_UP;
|
||||
}
|
||||
} else {
|
||||
// No. Is it down now?
|
||||
if ((regs.x.bx & MOUSE_LEFT_BUTTON) > 0) {
|
||||
// Yes! Set bit and DOWN event.
|
||||
event->buttons |= BUTTON_LEFT;
|
||||
event->flags |= EVENT_FLAG_LEFT_DOWN;
|
||||
} else {
|
||||
// No. Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
// Was the right button down?
|
||||
if (event->buttons & BUTTON_RIGHT) {
|
||||
// Yes. Is it still down?
|
||||
if ((regs.x.bx & MOUSE_RIGHT_BUTTON) > 0) {
|
||||
// Yes. Do nothing.
|
||||
} else {
|
||||
// No! Clear it and set UP event.
|
||||
event->buttons &= ~BUTTON_RIGHT;
|
||||
event->flags |= EVENT_FLAG_RIGHT_UP;
|
||||
}
|
||||
} else {
|
||||
// No. Is it down now?
|
||||
if ((regs.x.bx & MOUSE_RIGHT_BUTTON) > 0) {
|
||||
// Yes! Set bit and DOWN event.
|
||||
event->buttons |= BUTTON_RIGHT;
|
||||
event->flags |= EVENT_FLAG_RIGHT_DOWN;
|
||||
} else {
|
||||
// No. Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
// Read keyboard.
|
||||
event->key = 0;
|
||||
event->kbstat = 0;
|
||||
if (ext > 0) {
|
||||
key = bioskey(KEYBOARD_READ_EXTENDED);
|
||||
// The value returned is a combination of the key's scan code in the high 8 bits
|
||||
// and its ASCII code in the low 8 bits. For non-alphanumeric keys, such as the
|
||||
// arrow keys, the low 8 bits are zeroed.
|
||||
// Extended keys have the E0h prefix in the low 8 bits.
|
||||
event->flags |= EVENT_FLAG_KEYPRESS;
|
||||
if (LOW_BYTE(key) == 0xE0) {
|
||||
//_extended = 1;
|
||||
event->key = HIGH_BYTE(key);
|
||||
} else {
|
||||
//_extended = 0;
|
||||
event->key = LOW_BYTE(key);
|
||||
}
|
||||
if ((meta & (1 << KEY_META_ALT)) + (meta & (1 << KEY_META_ALT_LEFT)) + (meta & (1 << KEY_META_ALT_RIGHT))) event->kbstat |= META_ALT;
|
||||
if ((meta & (1 << KEY_META_CONTROL)) + (meta & (1 << KEY_META_CONTROL_LEFT)) + (meta & (1 << KEY_META_CONTROL_RIGHT))) event->kbstat |= META_CTRL;
|
||||
if ((meta & (1 << KEY_META_SHIFT_LEFT)) + (meta & (1 << KEY_META_SHIFT_RIGHT))) event->kbstat |= META_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,6 +285,8 @@ void platformShutdown(void) {
|
|||
__dpmi_regs r;
|
||||
__dpmi_meminfo m;
|
||||
|
||||
free(__guiBaseColors);
|
||||
|
||||
if (_vbeSurface.vbeInitBoolean == 0) {
|
||||
r.x.ax = 0x03; // make sure we're in 3h
|
||||
__dpmi_int(0x10, &r); // for buggy vesa implementations
|
||||
|
@ -192,32 +323,51 @@ void platformShutdown(void) {
|
|||
}
|
||||
|
||||
|
||||
void platformStartup(int16_t width, int16_t height, int16_t depth) {
|
||||
uint8_t platformStartup(int16_t width, int16_t height, int16_t depth) {
|
||||
uint16_t vbeModeNumber;
|
||||
uint8_t i;
|
||||
uint8_t EGA[16][3] = {
|
||||
{ 0, 0, 0 }, /* black */
|
||||
{ 0, 0, 170 }, /* blue */
|
||||
{ 0, 170, 0 }, /* green */
|
||||
{ 0, 170, 170 }, /* cyan */
|
||||
{ 170, 0, 0 }, /* red */
|
||||
{ 170, 0, 170 }, /* magenta */
|
||||
{ 170, 85, 0 }, /* brown */
|
||||
{ 170, 170, 170 }, /* light gray */
|
||||
{ 85, 85, 85 }, /* dark gray */
|
||||
{ 85, 85, 255 }, /* light blue */
|
||||
{ 85, 255, 85 }, /* light green */
|
||||
{ 85, 255, 255 }, /* light cyan */
|
||||
{ 255, 85, 85 }, /* light red */
|
||||
{ 255, 85, 255 }, /* light magenta */
|
||||
{ 255, 255, 85 }, /* yellow */
|
||||
{ 255, 255, 255 } /* white */
|
||||
};
|
||||
|
||||
if (vbeGetInfo() == NULL) {
|
||||
//logWrite("No VESA BIOS Extensions found.\n");
|
||||
//vbeShutdown();
|
||||
return;
|
||||
logWrite("No VESA BIOS Extensions found.\n");
|
||||
platformShutdown();
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (_vbeInfo.vbeVersion < 0x0200) {
|
||||
//logWrite("VBE Version 2.0 or better required.\n");
|
||||
//vbeShutdown();
|
||||
return;
|
||||
logWrite("VBE Version 2.0 or better required.\n");
|
||||
platformShutdown();
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
vbeGetPmodeInterface();
|
||||
|
||||
if ((vbeModeNumber = vbeSelectModeNumber(width, height, depth)) == 0) {
|
||||
//logWrite("No appropriate video mode available.\n");
|
||||
//vbeShutdown();
|
||||
return;
|
||||
logWrite("No appropriate video mode available.\n");
|
||||
platformShutdown();
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (vbeSetMode(vbeModeNumber) == NULL) {
|
||||
//vbeShutdown();
|
||||
return;
|
||||
platformShutdown();
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (_vbeSurface.bitsPerPixel == 8) videoSurfacePixelSet = videoSurfacePixelSet8;
|
||||
|
@ -225,6 +375,12 @@ void platformStartup(int16_t width, int16_t height, int16_t depth) {
|
|||
if (_vbeSurface.bitsPerPixel == 15) videoSurfacePixelSet = videoSurfacePixelSet16;
|
||||
if (_vbeSurface.bitsPerPixel == 32) videoSurfacePixelSet = videoSurfacePixelSet32;
|
||||
|
||||
__guiBaseColors = (ColorT *)malloc(sizeof(ColorT) * 16);
|
||||
for (i=0; i<16; i++) {
|
||||
__guiBaseColors[i] = videoColorMake(EGA[i][0], EGA[i][1], EGA[i][2]);
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
@ -414,12 +570,15 @@ static uint8_t vbeIsDesiredMode(void) {
|
|||
if (((_vbeModeInfo.modeAttributes) & (1<<7)) >> 7) {
|
||||
// Packed or Direct Color mode.
|
||||
if (_vbeModeInfo.memoryModel == VBE_MM_PACKED || _vbeModeInfo.memoryModel == VBE_MM_DCOLOR) {
|
||||
// Resolution minimum of 640x480.
|
||||
if (_vbeModeInfo.xResolution >= 640 && _vbeModeInfo.yResolution >= 480) {
|
||||
// Multiple of 8
|
||||
if (DIVISIBLE_BY_EIGHT(_vbeModeInfo.xResolution) && DIVISIBLE_BY_EIGHT(_vbeModeInfo.yResolution)) {
|
||||
// Valid mode!
|
||||
return 1;
|
||||
// We only handle these bit depths.
|
||||
if ((_vbeModeInfo.bitsPerPixel == 8) || (_vbeModeInfo.bitsPerPixel == 15) || (_vbeModeInfo.bitsPerPixel == 16) || (_vbeModeInfo.bitsPerPixel == 32)) {
|
||||
// Resolution minimum of 640x480.
|
||||
if (_vbeModeInfo.xResolution >= 640 && _vbeModeInfo.yResolution >= 480) {
|
||||
// Multiple of 8
|
||||
if (DIVISIBLE_BY_EIGHT(_vbeModeInfo.xResolution) && DIVISIBLE_BY_EIGHT(_vbeModeInfo.yResolution)) {
|
||||
// Valid mode!
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -568,7 +727,61 @@ uint16_t videoDisplayWidthGet(void) {
|
|||
|
||||
|
||||
void videoModesShow(void) {
|
||||
int8_t counter;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
//printf("VBE 2.0 driver v1.0 (c) 2021, Scott Duensing <scott@kangaroopunch.com>\n");
|
||||
//printf("Based on: VBE 2.0 driver v1.0 (c) 1999, Tobias Koch <tobias.koch@gmail.com>\n\n");
|
||||
|
||||
if (vbeGetInfo() == NULL) {
|
||||
logWrite("No VESA BIOS Extensions found.\n");
|
||||
platformShutdown();
|
||||
return;
|
||||
}
|
||||
logWrite(
|
||||
"Video Memory - %d KB\n"
|
||||
"VBE Version - %d.%d detected\n"
|
||||
"OEM Specification - %s\n",
|
||||
_vbeInfo.totalMemory * 64,
|
||||
_vbeInfo.vbeVersion >> 8, _vbeInfo.vbeVersion & 0x00FF,
|
||||
_vbeInfo.oemStringPtr);
|
||||
|
||||
if (_vbeInfo.vbeVersion >= 0x0200) {
|
||||
logWrite(
|
||||
"OEM Software Revision - %d.%d\n"
|
||||
"OEM Vendor Name - %s\n"
|
||||
"OEM Product Name - %s\n"
|
||||
"OEM Product Revision - %s\n"
|
||||
"Protected Mode Interface - %s\n\n",
|
||||
_vbeInfo.oemSoftwareRev >> 8, _vbeInfo.oemSoftwareRev & 0x00FF,
|
||||
_vbeInfo.oemVendorNamePtr,
|
||||
_vbeInfo.oemProductNamePtr,
|
||||
_vbeInfo.oemProductRevPtr,
|
||||
vbeGetPmodeInterface() ? "Found" : "Missing");
|
||||
} else {
|
||||
logWrite("VESA BIOS Extension 2.0 or better required!\n");
|
||||
platformShutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
for (counter=0; ; counter++) {
|
||||
if (_vbeInfo.videoModePtr[counter] == 0xFFFF) break;
|
||||
vbeGetModeInfo(_vbeInfo.videoModePtr[counter]);
|
||||
if (vbeIsDesiredMode()) {
|
||||
logWrite("Mode %Xh - %4d x %4d x %2d - RGB %d:%d:%d - %s\n",
|
||||
_vbeInfo.videoModePtr[counter],
|
||||
_vbeModeInfo.xResolution,
|
||||
_vbeModeInfo.yResolution,
|
||||
_vbeModeInfo.bitsPerPixel,
|
||||
_vbeModeInfo.redMaskSize,
|
||||
_vbeModeInfo.greenMaskSize,
|
||||
_vbeModeInfo.blueMaskSize,
|
||||
((_vbeModeInfo.memoryModel / 2) - 2) ? "DCOLOR" : "PACKED");
|
||||
}
|
||||
}
|
||||
|
||||
platformShutdown();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#endif
|
||||
|
||||
|
||||
void platformShutdown(void);
|
||||
void platformStartup(int16_t width, int16_t height, int16_t depth);
|
||||
void platformShutdown(void);
|
||||
uint8_t platformStartup(int16_t width, int16_t height, int16_t depth);
|
||||
|
||||
void videoModesShow(void);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
|
||||
#include "os.h"
|
||||
|
||||
#include "thirdparty/stb_ds.h"
|
||||
|
||||
|
||||
|
|
93
shared/log.c
Normal file
93
shared/log.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
// ***TODO*** On DOS, open and close the log on every write so the file gets updated and we still have data on a crash.
|
||||
|
||||
|
||||
#include "log.h"
|
||||
|
||||
|
||||
static FILE *_log = NULL;
|
||||
static uint8_t _ourHandle = 0;
|
||||
static char *_logBuffer = NULL;
|
||||
static uint16_t _logBufferSize = 0;
|
||||
static logCallback _logCallback = NULL;
|
||||
|
||||
|
||||
void logCallbackSet(logCallback callback) {
|
||||
_logCallback = callback;
|
||||
}
|
||||
|
||||
|
||||
void logClose(void) {
|
||||
if (_log && _ourHandle) {
|
||||
fclose(_log);
|
||||
_ourHandle = 0;
|
||||
}
|
||||
DEL(_logBuffer);
|
||||
}
|
||||
|
||||
|
||||
uint8_t logOpen(char *filename, uint8_t append) {
|
||||
_log = fopen(filename, append ? "a" : "w");
|
||||
if (_log) {
|
||||
_ourHandle = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void logOpenByHandle(FILE *handle) {
|
||||
_log = handle;
|
||||
}
|
||||
|
||||
|
||||
void logWrite(char *format, ...) {
|
||||
va_list args = { 0 };
|
||||
va_list args2 = { 0 };
|
||||
uint16_t length = 0;
|
||||
|
||||
if (_log) {
|
||||
va_start(args, format);
|
||||
va_copy(args2, args);
|
||||
|
||||
// Attempt to write into current log buffer.
|
||||
length = vsnprintf(_logBuffer, _logBufferSize, format, args);
|
||||
|
||||
// Did it fit?
|
||||
if (length >= _logBufferSize) {
|
||||
// Nope. Resize buffer to fit plus a bit more.
|
||||
if (_logBuffer) free(_logBuffer);
|
||||
_logBufferSize = length + 32;
|
||||
_logBuffer = (char *)malloc(_logBufferSize);
|
||||
// Do it again.
|
||||
vsnprintf(_logBuffer, _logBufferSize, format, args2);
|
||||
}
|
||||
|
||||
//#ifdef __linux__
|
||||
// Also output to stdout on Linux.
|
||||
fprintf(stdout, "%s", _logBuffer);
|
||||
fflush(stdout);
|
||||
//#endif
|
||||
|
||||
if (_logCallback) _logCallback(_logBuffer);
|
||||
|
||||
fprintf(_log, "%s", _logBuffer);
|
||||
fflush(_log);
|
||||
|
||||
va_end(args2);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void logWriteToFileOnly(char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
if (_log) {
|
||||
vfprintf(_log, format, args);
|
||||
fflush(_log);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
19
shared/log.h
Normal file
19
shared/log.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
|
||||
#include "os.h"
|
||||
|
||||
|
||||
typedef void (*logCallback)(char *message);
|
||||
|
||||
|
||||
void logCallbackSet(logCallback callback);
|
||||
void logClose(void);
|
||||
uint8_t logOpen(char *filename, uint8_t append);
|
||||
void logOpenByHandle(FILE *handle);
|
||||
void logWrite(char *format, ...);
|
||||
void logWriteToFileOnly(char *format, ...);
|
||||
|
||||
|
||||
#endif // LOG_H
|
|
@ -12,6 +12,13 @@
|
|||
#define DEL(v) {if(v) {free(v); v=NULL;}}
|
||||
|
||||
|
||||
// Some helper defines.
|
||||
#define DIVISIBLE_BY_EIGHT(x) ((((x) >> 3) << 3) == (x))
|
||||
#define HIGH_BYTE(b) ((uint8_t)(((b) & 0xFF00) >> 8))
|
||||
#define LOW_BYTE(b) ((uint8_t)((b) & 0x00FF))
|
||||
|
||||
|
||||
// Return codes.
|
||||
#define SUCCESS 0
|
||||
#define FAIL 1
|
||||
|
||||
|
|
|
@ -1 +1,51 @@
|
|||
#include "memory.h"
|
||||
|
||||
|
||||
FILE *_memoryLog = NULL;
|
||||
|
||||
|
||||
#ifdef MEMORY_CHECK_ENABLED
|
||||
void mwLogW(FILE *p);
|
||||
#endif
|
||||
|
||||
|
||||
FILE *memoryLogHandleGet(void) {
|
||||
return _memoryLog;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MEMORY_CHECK_ENABLED
|
||||
void memoryOutput(int c) {
|
||||
fputc(c, _memoryLog);
|
||||
fflush(_memoryLog);
|
||||
|
||||
#ifdef __linux__
|
||||
// Also output to stdout on Linux.
|
||||
fputc(c, stdout);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void memoryShutdown(void) {
|
||||
#ifdef MEMORY_CHECK_ENABLED
|
||||
unlink("memwatch.log"); // It just insists on creating this!
|
||||
mwTerm();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void memoryStartup(char *appName) {
|
||||
char *logName = utilAppNameWithNewExtensionGet(appName, "log");
|
||||
|
||||
_memoryLog = fopen(logName, "w");
|
||||
|
||||
#ifdef MEMORY_CHECK_ENABLED
|
||||
mwLogW(_memoryLog);
|
||||
mwSetOutFunc(memoryOutput);
|
||||
mwInit();
|
||||
#endif
|
||||
|
||||
free(logName);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,16 @@
|
|||
|
||||
#include "os.h"
|
||||
|
||||
|
||||
#ifdef MEMORY_CHECK_ENABLED
|
||||
#define MEMWATCH
|
||||
#include "thirdparty/memwatch/memwatch.h"
|
||||
#endif
|
||||
|
||||
|
||||
FILE *memoryLogHandleGet(void);
|
||||
void memoryShutdown(void);
|
||||
void memoryStartup(char *appName);
|
||||
|
||||
|
||||
#endif // MEMORY_H
|
||||
|
|
1590
shared/thirdparty/stb_ds.h
vendored
1590
shared/thirdparty/stb_ds.h
vendored
File diff suppressed because it is too large
Load diff
181
shared/util.c
Normal file
181
shared/util.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
#include "array.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
char __scratch[SCRATCH_SIZE];
|
||||
|
||||
|
||||
char *utilAppNameWithNewExtensionGet(char *appName, char *extension) {
|
||||
char *c = NULL;
|
||||
char *newName = NULL;
|
||||
int16_t x = strlen(appName);
|
||||
uint16_t len = 2 + strlen(extension); // 2 = dot in extension and 0 terminator.
|
||||
|
||||
// Find last portion of filename.
|
||||
while (x > 0) {
|
||||
if (appName[x] == '/' || appName[x] == '\\') break;
|
||||
x--;
|
||||
len++;
|
||||
}
|
||||
|
||||
// We use this + length of new extension for new string length.
|
||||
newName = (char *)malloc(len);
|
||||
if (newName) {
|
||||
if (strlen(appName) - x < len) {
|
||||
// Replace extension
|
||||
strncpy(newName, &appName[x + 1], len - 1);
|
||||
c = strstr(newName, ".");
|
||||
if (c) *c = 0;
|
||||
strncat(newName, ".", len - 1);
|
||||
strncat(newName, extension, len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return newName;
|
||||
}
|
||||
|
||||
|
||||
void utilBitsPrint(uint8_t byte) {
|
||||
int i = 0;
|
||||
|
||||
for (i = 7; 0 <= i; i--) {
|
||||
printf("%c", (byte & (1 << i)) ? '1' : '0');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *utilCreateString(char *format, ...) {
|
||||
va_list args;
|
||||
char *string;
|
||||
|
||||
va_start(args, format);
|
||||
string = utilCreateStringVArgs(format, args);
|
||||
va_end(args);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((__format__(__printf__, 1, 0)))
|
||||
char *utilCreateStringVArgs(char *format, va_list args) {
|
||||
va_list argsCopy;
|
||||
int32_t size = 0;
|
||||
char *buffer = NULL;
|
||||
|
||||
va_copy(argsCopy, args);
|
||||
size = vsnprintf(NULL, 0, format, argsCopy) + 1;
|
||||
va_end(argsCopy);
|
||||
buffer = calloc(1, (size_t)size);
|
||||
if (buffer) {
|
||||
vsnprintf(buffer, (size_t)size, format, args);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
void utilDie(const char *why, ...) {
|
||||
va_list args;
|
||||
char msg[2048];
|
||||
|
||||
va_start(args, why);
|
||||
vsprintf(msg, why, args);
|
||||
va_end(args);
|
||||
|
||||
logWrite("DIE: %s", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
uint8_t utilFileExists(char *filename) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
|
||||
if (f) {
|
||||
fclose(f);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
|
||||
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result) {
|
||||
unsigned char c;
|
||||
|
||||
// Get next byte.
|
||||
c = fgetc(f);
|
||||
// End of file?
|
||||
if (feof(f)) return FAIL;
|
||||
// Add to result.
|
||||
*result = c;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint8_t utilFromFileReadString(FILE *f, char **result) {
|
||||
unsigned char c;
|
||||
uint16_t x = 0;
|
||||
|
||||
// Something already in 'result'?
|
||||
DEL(*result);
|
||||
|
||||
while (1) {
|
||||
// Get next byte.
|
||||
c = fgetc(f);
|
||||
// End of file?
|
||||
if (feof(f)) return FAIL;
|
||||
// Add to result.
|
||||
__scratch[x++] = c;
|
||||
__scratch[x] = 0;
|
||||
// End of string?
|
||||
if (c == 0) {
|
||||
*result = strdup(__scratch);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void utilStringToLower(char *string) {
|
||||
uint16_t i;
|
||||
|
||||
for (i=0; i<strlen(string); i++) string[i] = tolower(string[i]);
|
||||
}
|
||||
|
||||
|
||||
char **utilWrapText(char *text, uint16_t width) {
|
||||
char **lines = NULL;
|
||||
char *head = text;
|
||||
char *buffer = NULL;
|
||||
int32_t bufferPos;
|
||||
int32_t pos;
|
||||
int32_t lastSpace;
|
||||
int32_t isLf;
|
||||
|
||||
buffer = (char *)malloc(width + 2);
|
||||
if (buffer) {
|
||||
pos = lastSpace = bufferPos = 0;
|
||||
while (head[pos] != 0) {
|
||||
isLf = (head[pos] == '\n');
|
||||
if (isLf || pos == width) {
|
||||
if (isLf || lastSpace == 0) lastSpace = pos; // just cut it
|
||||
while (*head!=0 && lastSpace-- > 0) {
|
||||
buffer[bufferPos++] = *head++;
|
||||
buffer[bufferPos] = 0;
|
||||
}
|
||||
arrput(lines, strdup(buffer));
|
||||
if (isLf) head++; // jump the line feed
|
||||
while (*head!=0 && *head==' ') head++; // clear the leading space
|
||||
lastSpace = pos = bufferPos = 0;
|
||||
} else {
|
||||
if (head[pos] == ' ') lastSpace = pos;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
arrput(lines, strdup(head));
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
26
shared/util.h
Normal file
26
shared/util.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
|
||||
#include "os.h"
|
||||
|
||||
|
||||
#define SCRATCH_SIZE 4096
|
||||
|
||||
|
||||
extern char __scratch[SCRATCH_SIZE];
|
||||
|
||||
|
||||
char *utilAppNameWithNewExtensionGet(char *appName, char *extension);
|
||||
void utilBitsPrint(uint8_t byte);
|
||||
char *utilCreateString(char *format, ...);
|
||||
char *utilCreateStringVArgs(char *format, va_list args);
|
||||
void utilDie(const char *why, ...);
|
||||
uint8_t utilFileExists(char *filename);
|
||||
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result);
|
||||
uint8_t utilFromFileReadString(FILE *f, char **result);
|
||||
void utilStringToLower(char *string);
|
||||
char **utilWrapText(char *text, uint16_t width);
|
||||
|
||||
|
||||
#endif // UTIL_H
|
Loading…
Add table
Reference in a new issue