Commit e4e271c5391dd16cd42f33978690accb5d118cdb

Commits
[COMMIT BEGIN]
commit e4e271c5391dd16cd42f33978690accb5d118cdb
Author: 0x4248 <[email protected]>
Date:   Thu Apr 2 17:05:18 2026 +0100

    IBM-PC/Dataworks: init

diff --git a/systems/IBM-PC/DataWorks/src/CLI.C b/systems/IBM-PC/DataWorks/src/CLI.C
new file mode 100644
index 0000000..48ac5bc
--- /dev/null
+++ b/systems/IBM-PC/DataWorks/src/CLI.C
@@ -0,0 +1,62 @@
+/* C89 Standard only */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "DW.H"
+
+static int dw_interact(const char *path)
+{
+	char line[DW_MAX_LINE];
+	char *tokens[8];
+	char *p;
+	int count;
+
+	printf("DataWorks interactive mode. Type HELP or EXIT.\n");
+	for (;;) {
+		printf("%s> ", path);
+		if (fgets(line, sizeof(line), stdin) == NULL) {
+			return 1;
+		}
+		dw_trim(line);
+		if (line[0] == '\0') {
+			continue;
+		}
+
+		count = 0;
+		p = strtok(line, " \t");
+		while (p != NULL && count < 8) {
+			tokens[count++] = p;
+			p = strtok(NULL, " \t");
+		}
+		if (count == 0) {
+			continue;
+		}
+
+		if (dw_stricmp(tokens[0], "EXIT") == 0 || dw_stricmp(tokens[0], "QUIT") == 0) {
+			return 1;
+		}
+		if (dw_stricmp(tokens[0], "HELP") == 0) {
+			dw_print_help();
+			continue;
+		}
+
+		if (!dw_run_command(path, count, tokens)) {
+			printf("Command failed.\n");
+		}
+	}
+}
+
+int dw_cli_main(int argc, char **argv)
+{
+	if (argc < 3) {
+		dw_print_help();
+		return 1;
+	}
+
+	if (dw_stricmp(argv[2], "INTERACT") == 0) {
+		return dw_interact(argv[1]) ? 0 : 1;
+	}
+
+	return dw_run_command(argv[1], argc - 2, argv + 2) ? 0 : 1;
+}
diff --git a/systems/IBM-PC/DataWorks/src/COMMAND.C b/systems/IBM-PC/DataWorks/src/COMMAND.C
new file mode 100644
index 0000000..9827db1
--- /dev/null
+++ b/systems/IBM-PC/DataWorks/src/COMMAND.C
@@ -0,0 +1,101 @@
+/* C89 Standard only */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "DW.H"
+
+void dw_print_help(void)
+{
+	printf("DataWorks (simple) commands:\n");
+	printf("  DW <file.dw> PRINT\n");
+	printf("  DW <file.dw> INSERT <value> $row,col\n");
+	printf("  DW <file.dw> DEL_COL [col_index]\n");
+	printf("  DW <file.dw> SET_COL_NAME <name> [col_index]\n");
+	printf("  DW <file.dw> INTERACT\n");
+	printf("Limits: %d rows, %d cols, cell size %d chars\n", DW_MAX_ROWS, DW_MAX_COLS, DW_MAX_CELL - 1);
+}
+
+int dw_run_command(const char *path, int argc, char **argv)
+{
+	DWTable table;
+	int row;
+	int col;
+	int col_index;
+	int ok;
+
+	if (argc < 1) {
+		return 0;
+	}
+
+	dw_init_table(&table);
+
+	if (!dw_load_file(path, &table)) {
+		printf("Error: failed to load %s\n", path);
+		dw_free_table(&table);
+		return 0;
+	}
+	ok = 1;
+
+	if (dw_stricmp(argv[0], "PRINT") == 0) {
+		dw_print_table(&table);
+	} else if (dw_stricmp(argv[0], "INSERT") == 0) {
+		if (argc < 3) {
+			printf("Usage: DW <file.dw> INSERT <value> $row,col\n");
+			ok = 0;
+			goto cleanup;
+		}
+		if (!dw_parse_cell_ref(argv[2], &row, &col)) {
+			printf("Error: invalid cell ref '%s'. Use $row,col\n", argv[2]);
+			ok = 0;
+			goto cleanup;
+		}
+		if (!dw_insert(&table, argv[1], row, col)) {
+			printf("Error: table limit reached\n");
+			ok = 0;
+			goto cleanup;
+		}
+		if (!dw_save_file(path, &table)) {
+			printf("Error: failed to save %s\n", path);
+			ok = 0;
+			goto cleanup;
+		}
+	} else if (dw_stricmp(argv[0], "DEL_COL") == 0) {
+		col_index = (argc >= 2) ? atoi(argv[1]) : (table.cols - 1);
+		if (!dw_del_col(&table, col_index)) {
+			printf("Error: invalid column index\n");
+			ok = 0;
+			goto cleanup;
+		}
+		if (!dw_save_file(path, &table)) {
+			printf("Error: failed to save %s\n", path);
+			ok = 0;
+			goto cleanup;
+		}
+	} else if (dw_stricmp(argv[0], "SET_COL_NAME") == 0) {
+		if (argc < 2) {
+			printf("Usage: DW <file.dw> SET_COL_NAME <name> [col_index]\n");
+			ok = 0;
+			goto cleanup;
+		}
+		col_index = (argc >= 3) ? atoi(argv[2]) : (table.cols - 1);
+		if (!dw_set_col_name(&table, col_index, argv[1])) {
+			printf("Error: invalid column index\n");
+			ok = 0;
+			goto cleanup;
+		}
+		if (!dw_save_file(path, &table)) {
+			printf("Error: failed to save %s\n", path);
+			ok = 0;
+			goto cleanup;
+		}
+	} else {
+		printf("Error: unknown command '%s'\n", argv[0]);
+		dw_print_help();
+		ok = 0;
+	}
+
+cleanup:
+	dw_free_table(&table);
+	return ok;
+}
diff --git a/systems/IBM-PC/DataWorks/src/DW.H b/systems/IBM-PC/DataWorks/src/DW.H
new file mode 100644
index 0000000..ca178c7
--- /dev/null
+++ b/systems/IBM-PC/DataWorks/src/DW.H
@@ -0,0 +1,36 @@
+#ifndef DW_H
+#define DW_H
+
+#define DW_SEP 31
+#define DW_MAX_LINE 4096
+#define DW_MAX_ROWS 256
+#define DW_MAX_COLS 64
+#define DW_MAX_CELL 128
+
+typedef struct {
+	int rows;
+	int cols;
+	char ***cells;
+} DWTable;
+
+void dw_trim(char *s);
+int dw_stricmp(const char *a, const char *b);
+void dw_copy_cell(char *dst, const char *src);
+int dw_parse_cell_ref(const char *text, int *row, int *col);
+
+void dw_init_table(DWTable *table);
+void dw_free_table(DWTable *table);
+int dw_load_file(const char *path, DWTable *table);
+int dw_save_file(const char *path, const DWTable *table);
+void dw_print_table(const DWTable *table);
+int dw_insert(DWTable *table, const char *value, int data_row, int col);
+int dw_del_col(DWTable *table, int col_index);
+int dw_set_col_name(DWTable *table, int col_index, const char *name);
+
+void dw_print_help(void);
+int dw_run_command(const char *path, int argc, char **argv);
+
+int dw_cli_main(int argc, char **argv);
+
+#endif
+
diff --git a/systems/IBM-PC/DataWorks/src/MAIN.C b/systems/IBM-PC/DataWorks/src/MAIN.C
new file mode 100644
index 0000000..7a91de1
--- /dev/null
+++ b/systems/IBM-PC/DataWorks/src/MAIN.C
@@ -0,0 +1,8 @@
+/* C89 Standard only */
+
+#include "DW.H"
+
+int main(int argc, char **argv)
+{
+	return dw_cli_main(argc, argv);
+}
diff --git a/systems/IBM-PC/DataWorks/src/TABLE.C b/systems/IBM-PC/DataWorks/src/TABLE.C
new file mode 100644
index 0000000..ea7000e
--- /dev/null
+++ b/systems/IBM-PC/DataWorks/src/TABLE.C
@@ -0,0 +1,310 @@
+/* C89 Standard only */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "DW.H"
+
+static int dw_alloc_cell(char **out_cell)
+{
+	*out_cell = (char *)malloc((size_t)DW_MAX_CELL);
+	if (*out_cell == NULL) {
+		return 0;
+	}
+	(*out_cell)[0] = '\0';
+	return 1;
+}
+
+static void dw_fill_header_names(DWTable *table, int start_col)
+{
+	int c;
+	char temp[32];
+
+	for (c = start_col; c < table->cols; ++c) {
+		if (table->cells[0][c] != NULL && table->cells[0][c][0] == '\0') {
+			sprintf(temp, "COL_%d", c);
+			dw_copy_cell(table->cells[0][c], temp);
+		}
+	}
+}
+
+static int dw_ensure_size(DWTable *table, int rows, int cols)
+{
+	int r;
+	int c;
+	int old_rows;
+	char ***new_rows;
+	char **new_row;
+
+	if (rows > DW_MAX_ROWS || cols > DW_MAX_COLS || rows < 1 || cols < 1) {
+		return 0;
+	}
+
+	old_rows = table->rows;
+
+	if (rows > table->rows) {
+		new_rows = (char ***)realloc(table->cells, (size_t)rows * sizeof(char **));
+		if (new_rows == NULL) {
+			return 0;
+		}
+		table->cells = new_rows;
+		for (r = table->rows; r < rows; ++r) {
+			table->cells[r] = NULL;
+		}
+		table->rows = rows;
+	}
+
+	if (table->cols > 0 && table->rows > old_rows) {
+		for (r = old_rows; r < table->rows; ++r) {
+			table->cells[r] = (char **)malloc((size_t)table->cols * sizeof(char *));
+			if (table->cells[r] == NULL) {
+				return 0;
+			}
+			for (c = 0; c < table->cols; ++c) {
+				table->cells[r][c] = NULL;
+				if (!dw_alloc_cell(&table->cells[r][c])) {
+					return 0;
+				}
+			}
+		}
+	}
+
+	if (cols > table->cols) {
+		for (r = 0; r < table->rows; ++r) {
+			new_row = (char **)realloc(table->cells[r], (size_t)cols * sizeof(char *));
+			if (new_row == NULL) {
+				return 0;
+			}
+			table->cells[r] = new_row;
+			for (c = table->cols; c < cols; ++c) {
+				table->cells[r][c] = NULL;
+				if (!dw_alloc_cell(&table->cells[r][c])) {
+					return 0;
+				}
+			}
+		}
+		table->cols = cols;
+		dw_fill_header_names(table, 0);
+	}
+
+	return 1;
+}
+
+void dw_init_table(DWTable *table)
+{
+	table->rows = 0;
+	table->cols = 0;
+	table->cells = NULL;
+
+	if (!dw_ensure_size(table, 1, 1)) {
+		return;
+	}
+
+	dw_copy_cell(table->cells[0][0], "COL_0");
+}
+
+void dw_free_table(DWTable *table)
+{
+	int r;
+	int c;
+
+	if (table->cells != NULL) {
+		for (r = 0; r < table->rows; ++r) {
+			if (table->cells[r] != NULL) {
+				for (c = 0; c < table->cols; ++c) {
+					free(table->cells[r][c]);
+				}
+				free(table->cells[r]);
+			}
+		}
+		free(table->cells);
+	}
+
+	table->rows = 0;
+	table->cols = 0;
+	table->cells = NULL;
+}
+
+int dw_load_file(const char *path, DWTable *table)
+{
+	FILE *fp;
+	char line[DW_MAX_LINE];
+	int row;
+	int col;
+	int pos;
+	int i;
+	char delim;
+	char cell[DW_MAX_CELL];
+
+	dw_init_table(table);
+	fp = fopen(path, "rb");
+	if (fp == NULL) {
+		return 1;
+	}
+
+	row = 0;
+	while (fgets(line, sizeof(line), fp) != NULL) {
+		dw_trim(line);
+		delim = (strchr(line, DW_SEP) != NULL) ? (char)DW_SEP : ',';
+
+		col = 0;
+		pos = 0;
+		cell[0] = '\0';
+
+		for (i = 0;; ++i) {
+			if (line[i] == delim || line[i] == '\0') {
+				cell[pos] = '\0';
+				dw_trim(cell);
+
+				if (!dw_ensure_size(table, row + 1, col + 1)) {
+					fclose(fp);
+					dw_free_table(table);
+					return 0;
+				}
+				dw_copy_cell(table->cells[row][col], cell);
+
+				++col;
+				pos = 0;
+				cell[0] = '\0';
+
+				if (line[i] == '\0' || col >= DW_MAX_COLS) {
+					break;
+				}
+			} else if (pos < DW_MAX_CELL - 1) {
+				cell[pos++] = line[i];
+			}
+		}
+
+		++row;
+		if (row >= DW_MAX_ROWS) {
+			break;
+		}
+	}
+
+	if (row > 0) {
+		table->rows = row;
+	}
+	dw_fill_header_names(table, 0);
+	fclose(fp);
+	return 1;
+}
+
+int dw_save_file(const char *path, const DWTable *table)
+{
+	FILE *fp;
+	int r;
+	int c;
+
+	fp = fopen(path, "wb");
+	if (fp == NULL) {
+		return 0;
+	}
+
+	for (r = 0; r < table->rows; ++r) {
+		for (c = 0; c < table->cols; ++c) {
+			if (table->cells[r][c] != NULL) {
+				fputs(table->cells[r][c], fp);
+			}
+			if (c < table->cols - 1) {
+				fputc(DW_SEP, fp);
+			}
+		}
+		fputc('\n', fp);
+	}
+
+	fclose(fp);
+	return 1;
+}
+
+void dw_print_table(const DWTable *table)
+{
+	int r;
+	int c;
+	int i;
+	int len;
+	int pad;
+	int widths[DW_MAX_COLS];
+
+	for (c = 0; c < table->cols; ++c) {
+		widths[c] = 0;
+	}
+
+	for (r = 0; r < table->rows; ++r) {
+		for (c = 0; c < table->cols; ++c) {
+			len = 0;
+			if (table->cells[r][c] != NULL) {
+				len = (int)strlen(table->cells[r][c]);
+			}
+			if (len > widths[c]) {
+				widths[c] = len;
+			}
+		}
+	}
+
+	for (r = 0; r < table->rows; ++r) {
+		for (c = 0; c < table->cols; ++c) {
+			if (table->cells[r][c] == NULL || table->cells[r][c][0] == '\0') {
+				printf("~");
+			} else {
+				printf("%s", table->cells[r][c]);
+			}
+			if (c < table->cols - 1) {
+				len = 0;
+				if (table->cells[r][c] != NULL) {
+					len = (int)strlen(table->cells[r][c]);
+				}
+				if (len == 0) {
+					len = 1;
+				}
+				pad = (widths[c] - len) + 4;
+				for (i = 0; i < pad; ++i) {
+					putchar(' ');
+				}
+			}
+		}
+		printf("\n");
+	}
+}
+
+int dw_insert(DWTable *table, const char *value, int data_row, int col)
+{
+	int real_row;
+
+	real_row = data_row + 1;
+	if (!dw_ensure_size(table, real_row + 1, col + 1)) {
+		return 0;
+	}
+	dw_copy_cell(table->cells[real_row][col], value);
+	return 1;
+}
+
+int dw_del_col(DWTable *table, int col_index)
+{
+	int r;
+	int c;
+
+	if (col_index < 0 || col_index >= table->cols || table->cols <= 0) {
+		return 0;
+	}
+
+	for (r = 0; r < table->rows; ++r) {
+		for (c = col_index; c < table->cols - 1; ++c) {
+			dw_copy_cell(table->cells[r][c], table->cells[r][c + 1]);
+		}
+		if (table->cells[r][table->cols - 1] != NULL) {
+			table->cells[r][table->cols - 1][0] = '\0';
+		}
+	}
+	table->cols -= 1;
+	return 1;
+}
+
+int dw_set_col_name(DWTable *table, int col_index, const char *name)
+{
+	if (col_index < 0 || col_index >= table->cols) {
+		return 0;
+	}
+	dw_copy_cell(table->cells[0][col_index], name);
+	return 1;
+}
diff --git a/systems/IBM-PC/DataWorks/src/UTIL.C b/systems/IBM-PC/DataWorks/src/UTIL.C
new file mode 100644
index 0000000..e4afcd7
--- /dev/null
+++ b/systems/IBM-PC/DataWorks/src/UTIL.C
@@ -0,0 +1,85 @@
+/* C89 Standard only */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "DW.H"
+
+void dw_trim(char *s)
+{
+	int len;
+	int i;
+	int start;
+
+	len = (int)strlen(s);
+	while (len > 0 && (s[len - 1] == '\n' || s[len - 1] == '\r' || isspace((unsigned char)s[len - 1]))) {
+		s[len - 1] = '\0';
+		--len;
+	}
+
+	start = 0;
+	while (s[start] != '\0' && isspace((unsigned char)s[start])) {
+		++start;
+	}
+
+	if (start > 0) {
+		i = 0;
+		while (s[start + i] != '\0') {
+			s[i] = s[start + i];
+			++i;
+		}
+		s[i] = '\0';
+	}
+}
+
+int dw_stricmp(const char *a, const char *b)
+{
+	unsigned char ca;
+	unsigned char cb;
+
+	while (*a != '\0' && *b != '\0') {
+		ca = (unsigned char)tolower((unsigned char)*a);
+		cb = (unsigned char)tolower((unsigned char)*b);
+		if (ca != cb) {
+			return (int)ca - (int)cb;
+		}
+		++a;
+		++b;
+	}
+	return (int)(unsigned char)*a - (int)(unsigned char)*b;
+}
+
+void dw_copy_cell(char *dst, const char *src)
+{
+	if (src == NULL) {
+		dst[0] = '\0';
+		return;
+	}
+	strncpy(dst, src, DW_MAX_CELL - 1);
+	dst[DW_MAX_CELL - 1] = '\0';
+}
+
+int dw_parse_cell_ref(const char *text, int *row, int *col)
+{
+	char *endptr;
+	long r;
+	long c;
+
+	if (text == NULL || text[0] != '$') {
+		return 0;
+	}
+
+	r = strtol(text + 1, &endptr, 10);
+	if (*endptr != ',' || r < 0) {
+		return 0;
+	}
+	c = strtol(endptr + 1, &endptr, 10);
+	if (*endptr != '\0' || c < 0) {
+		return 0;
+	}
+
+	*row = (int)r;
+	*col = (int)c;
+	return 1;
+}
diff --git a/systems/IBM-PC/PhotonX/VGA.md b/systems/IBM-PC/PhotonX/VGA.md
new file mode 100644
index 0000000..fc8ed19
--- /dev/null
+++ b/systems/IBM-PC/PhotonX/VGA.md
@@ -0,0 +1,101 @@
+# VGA Subsystem
+
+PhotonX Graphics SDK — VGA driver interface for 8086/8088 systems.
+
+## Overview
+
+The VGA subsystem exposes two distinct APIs depending on the active video mode:
+a text-mode API for 80x25 character output, and a graphics-mode API for direct
+pixel rendering in mode 13h (320x200, 256 colors).
+
+<!-- #ifndef VGA_H
+#define VGA_H
+
+#include <dos.h>
+
+#define VGA_SEG 0xA000
+#define VGA_MODE_TEXT_80x25 0x03
+#define VGA_MODE_320x200x256 0x13
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+
+extern unsigned char far *vga;
+
+/* Core mode + utility */
+void vga_set_mode(uint8_t mode);
+
+/* Text mode API (whitepaper-aligned) */
+void vga_text_setcolor(uint8_t fg, uint8_t bg);
+void vga_text_gotoxy(uint8_t x, uint8_t y);
+void vga_text_putch(char c);
+void vga_text_puts(const char *str);
+void vga_text_cls(void);
+
+/* Graphics mode API (whitepaper-aligned) */
+void vga_set_palette(uint8_t index, uint8_t r, uint8_t g, uint8_t b);
+void vga_gfx_setclscolor(uint8_t color);
+void vga_gfx_cls(void);
+void vga_gfx_putpixel(uint16_t x, uint16_t y, uint8_t color);
+void vga_gfx_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t color);
+void vga_gfx_rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t color);
+void vga_gfx_circle(uint16_t x, uint16_t y, uint16_t radius, uint8_t color);
+void vga_gfx_putch(char c, int x, int y, uint8_t color);
+void vga_gfx_puts(const char *str, int x, int y, uint8_t color);
+
+/* Compatibility names for existing code */
+void set_mode(unsigned char mode);
+void set_palette(unsigned char index, unsigned char r, unsigned char g, unsigned char b);
+void clear_screen(unsigned char color);
+void put_pixel(int x, int y, unsigned char color);
+
+#endif -->
+
+## Setting mode outputs
+
+To switch between text and graphics modes, use the `vga_set_mode` function with 
+the appropriate mode constant:
+
+```c
+vga_set_mode(VGA_MODE_TEXT_80x25); // Switch to text mode
+vga_set_mode(VGA_MODE_320x200x256); // Switch to graphics mode
+```
+
+**WARNING**: It is always important to reset the screen mode back to text mode
+before returning the user to the MS-DOS environment, otherwise they will be left
+almost like a broken state and could lead to unexpected behavior - It is also
+noted that on MS-DOS the `cls` command does not reset the screen mode. For simple
+way to reset the screen mode you should call these functions:
+
+```c
+vga_set_mode(VGA_MODE_TEXT_80x25); // Reset to text mode
+vga_text_setcolor(7, 0); // Set default white on black text color
+vga_text_cls(); // Clear the screen
+```
+## Text Mode
+
+In text mode, you get a character grid of 80 columns and 25 rows and 16 colors.
+
+### Color palette 
+
+The VGA text mode supports a fixed palette of 16 colors, indexed from 0 to 15:
+
+<table>
+  <tr><th>Index</th><th>Color name</th><th>Color HTML</th></tr>
+  <tr><td>0</td><td>Black</td><td style="background:#000000;color:#ffffff;">#000000</td></tr>
+  <tr><td>1</td><td>Blue</td><td style="background:#0000AA;color:#ffffff;">#0000AA</td></tr>
+  <tr><td>2</td><td>Green</td><td style="background:#00AA00;color:#ffffff;">#00AA00</td></tr>
+  <tr><td>3</td><td>Cyan</td><td style="background:#00AAAA;color:#000000;">#00AAAA</td></tr>
+  <tr><td>4</td><td>Red</td><td style="background:#AA0000;color:#ffffff;">#AA0000</td></tr>
+  <tr><td>5</td><td>Magenta</td><td style="background:#AA00AA;color:#ffffff;">#AA00AA</td></tr>
+  <tr><td>6</td><td>Brown</td><td style="background:#AA5500;color:#ffffff;">#AA5500</td></tr>
+  <tr><td>7</td><td>Light Gray</td><td style="background:#AAAAAA;color:#000000;">#AAAAAA</td></tr>
+  <tr><td>8</td><td>Dark Gray</td><td style="background:#555555;color:#ffffff;">#555555</td></tr>
+  <tr><td>9</td><td>Light Blue</td><td style="background:#5555FF;color:#ffffff;">#5555FF</td></tr>
+  <tr><td>10</td><td>Light Green</td><td style="background:#55FF55;color:#000000;">#55FF55</td></tr>
+  <tr><td>11</td><td>Light Cyan</td><td style="background:#55FFFF;color:#000000;">#55FFFF</td></tr>
+  <tr><td>12</td><td>Light Red</td><td style="background:#FF5555;color:#000000;">#FF5555</td></tr>
+  <tr><td>13</td><td>Light Magenta</td><td style="background:#FF55FF;color:#000000;">#FF55FF</td></tr>
+  <tr><td>14</td><td>Yellow</td><td style="background:#FFFF55;color:#000000;">#FFFF55</td></tr>
+  <tr><td>15</td><td>White</td><td style="background:#FFFFFF;color:#000000;">#FFFFFF</td></tr>
+</table>
\ No newline at end of file
diff --git a/systems/IBM-PC/PhotonX/src/demos/TEXTT.C b/systems/IBM-PC/PhotonX/src/demos/TEXTT.C
new file mode 100644
index 0000000..48341d4
--- /dev/null
+++ b/systems/IBM-PC/PhotonX/src/demos/TEXTT.C
@@ -0,0 +1,89 @@
+#include "VGA.H"
+#include <conio.h>
+
+int main()
+{
+    unsigned char i;
+    unsigned char j;
+    const char *color_names[16] = {
+        "Black",
+        "Blue",
+        "Green",
+        "Cyan",
+        "Red",
+        "Magenta",
+        "Brown",
+        "Light Gray",
+        "Dark Gray",
+        "Light Blue",
+        "Light Green",
+        "Light Cyan",
+        "Light Red",
+        "Light Magenta",
+        "Yellow",
+        "White"
+    };
+    const char *logo[11] = {
+        "               ",
+        "               ",
+        "    `7MMF'     ",
+        " ,mmmmMMmmmm.  ",
+        "6MP   MM   YMb ",
+        "8M    MM    M8 ",
+        "YMb   MM   dM9 ",
+        " `YmmmMMmmmP'  ",
+        "    .JMML.     ",
+        "               ",
+        "               "
+    };
+
+    vga_set_mode(VGA_MODE_TEXT_80x25);
+    vga_text_setcolor(15, 1);
+    vga_text_cls();
+    vga_text_gotoxy(0, 0);
+    vga_text_puts("PhotonX Demo: Text Colors\r\n");
+
+    vga_text_setcolor(14, 0);
+    vga_text_puts("Index shown with matching foreground color:\r\n\r\n");
+
+    vga_text_setcolor(15, 0);
+    for (j = 0; j < 11; ++j)
+    {
+        vga_text_gotoxy(60, 5 + j);
+        vga_text_puts(logo[j]);
+    }
+
+    vga_text_gotoxy(0, 3);
+
+    for (i = 0; i < 16; ++i)
+    {
+        if (i == 0)
+            vga_text_setcolor(i, 7);
+        else
+            vga_text_setcolor(i, 0);
+
+        vga_text_puts("Color ");
+
+        if (i < 10)
+            vga_text_putch('0' + i);
+        else
+        {
+            vga_text_putch('1');
+            vga_text_putch('0' + (i - 10));
+        }
+
+        vga_text_puts(": ");
+        vga_text_puts(color_names[i]);
+        vga_text_puts("\r\n");
+    }
+
+    vga_text_setcolor(15, 0);
+    vga_text_puts("\r\nPress any key to exit...\r\n");
+    getch();
+
+    vga_set_mode(VGA_MODE_TEXT_80x25);
+    vga_text_setcolor(15, 0);
+    vga_text_cls();
+
+    return 0;
+}
[COMMIT END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.