2021-12-14 22:56:42 +10:00

575 lines
12 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "font.h"
#include "quinn.h"
#include "convertxpm.h"
#include "terminal.xpm"
extern const struct bitmap_font bmapfont;
int term_w;
int term_h;
int window_handle = -1;
#define ParentRead read_pipe[0]
#define ParentWrite write_pipe[1]
#define ChildRead write_pipe[0]
#define ChildWrite read_pipe[1]
extern char **environ;
int read_pipe[2];
int write_pipe[2];
char *surface;
unsigned char attrib;
int term_x;
int term_y;
int echo = 1;
unsigned int char_width, char_height;
char *cursor_save_buffer;
int cursor_save_x;
int cursor_save_y;
static int state = 0;
static int params[16];
static int param_count = 0;
static int saved_x = 0;
static int saved_y = 0;
static int bold = 0;
static unsigned char saved_attr = 0x07;
static unsigned int console_col_map[16] = {
0xff000000, 0xff0000AA, 0xff00AA00, 0xff00AAAA,
0xffAA0000, 0xffAA00AA, 0xffAA5500, 0xffAAAAAA,
0xff555555, 0xff5555FF, 0xff55FF55, 0xff55FFFF,
0xffFF5555, 0xffFF55FF, 0xffFFFF55, 0xffFFFFFF
};
void update_cursor(int restore) {
int bpos, i, j;
if (restore == 1 && cursor_save_x > -1 && cursor_save_y > -1) {
// restore the bit of the screen where the cursor was
bpos = 0;
for (i=0;i<4;i++) {
for (j=0;j<8;j++) {
int where = ((j + (cursor_save_x*bmapfont.Width)) * 4) + (((bmapfont.Height - i - 1) + (cursor_save_y* bmapfont.Height)) * term_w * 4);
surface[where] = cursor_save_buffer[bpos]; // BLUE
surface[where + 1] = cursor_save_buffer[bpos + 1]; // GREEN
surface[where + 2] = cursor_save_buffer[bpos + 2]; // RED
surface[where + 3] = cursor_save_buffer[bpos + 3]; // ALPHA
bpos += 4;
}
}
}
// save the new cursor position buffer;
bpos = 0;
for (i=0;i<4;i++) {
for (j=0;j<8;j++) {
int where = ((j + (term_x*bmapfont.Width)) * 4) + (((bmapfont.Height - i - 1) + (term_y* bmapfont.Height)) * term_w * 4);
cursor_save_buffer[bpos] = surface[where];
cursor_save_buffer[bpos + 1] = surface[where + 1];
cursor_save_buffer[bpos + 2] = surface[where + 2];
cursor_save_buffer[bpos + 3] = surface[where + 3];
bpos += 4;
}
}
cursor_save_x = term_x;
cursor_save_y = term_y;
// draw the cursor
for (i=0;i<4;i++) {
for (j=0;j<8;j++) {
int where = ((j + (cursor_save_x*bmapfont.Width)) * 4) + (((bmapfont.Height - i - 1) + (cursor_save_y* bmapfont.Height)) * term_w * 4);
surface[where] = 0xff; // BLUE
surface[where + 1] = 0xff; // GREEN
surface[where + 2] = 0xff; // RED
surface[where + 3] = 0xff;
bpos += 4;
}
}
}
void goto_xy(int newx, int newy) {
if (newx > char_width || newy > char_height || newx < 0 || newy < 0) {
return;
}
term_x = newx;
term_y = newy;
update_cursor(1);
}
void clear_screen(void) {
int j;
int k;
unsigned int colour = console_col_map[(attrib & 0xf0) >> 4];
for (k=0;k<term_w;k++) {
for (j=0;j<term_h;j++) {
quinn_setpixel(window_handle, surface, k, j, term_w, term_h, colour);
}
}
}
void scroll_up(void) {
unsigned char *read_ptr = surface + (bmapfont.Height * (80 * bmapfont.Width * 4));
unsigned char *write_ptr = surface;
unsigned int num_bytes = ((80 * bmapfont.Width * 4) * term_h) - ((80 * bmapfont.Width * 4) * bmapfont.Height);
memcpy(write_ptr, read_ptr, num_bytes);
read_ptr = (unsigned char *) surface + ((80 * bmapfont.Width * 4) * term_h) - ((80 * bmapfont.Width * 4) * bmapfont.Height);
for (int i = 0; i < (80 * bmapfont.Width * 4) * bmapfont.Height; i += 4) {
read_ptr[i] = 0;
read_ptr[i+1] = 0;
read_ptr[i+2] = 0;
read_ptr[i+3] = 0xff;
}
cursor_save_y--;
}
void draw_char(int x, int y, unsigned char c) {
int i;
for (i=0;i<bmapfont.Chars;i++) {
if (bmapfont.Index[i] == c) break;
}
const char *font_char = &bmapfont.Bitmap[i * bmapfont.Height];
int cx,cy;
int mask[8]={128,64,32,16,8,4,2,1};
unsigned int fgcolor = console_col_map[attrib & 0x0F];
unsigned int bgcolor = console_col_map[(attrib & 0xF0) >> 4];
for(cy=0;cy<16;cy++){
for(cx=0;cx<8;cx++){
quinn_setpixel(window_handle, surface, x+cx, y+cy, term_w, term_h, font_char[cy] & mask[cx] ? fgcolor:bgcolor);
}
}
}
void console_backspace() {
if (term_x == 0) {
term_y--;
term_x = char_width - 1;
} else {
term_x--;
}
draw_char(term_x * bmapfont.Width, term_y * bmapfont.Height, ' ');
update_cursor(1);
}
void put_char(unsigned char c) {
draw_char(term_x * (int)bmapfont.Width, term_y * (int)bmapfont.Height, c);
term_x++;
update_cursor(0);
}
void process_char(char c) {
int j, k;
if (term_x == char_width) {
term_x = 0;
term_y++;
}
if (term_y == char_height) {
scroll_up();
term_y = char_height - 1;
}
if (state == 0) {
if (c == 27) {
state = 1;
return;
} else {
if (c == '\n') {
term_x = 0;
term_y++;
if (term_y == char_height) {
scroll_up();
term_y = char_height - 1;
}
update_cursor(1);
} else if ((unsigned char)c > 31) {
put_char((unsigned char)c);
}
}
} else if (state == 1) {
if (c == '[') {
state = 2;
return;
}
} else if (state == 2) {
param_count = 0;
for (j=0;j<16;j++) {
params[j] = 0;
}
state = 3;
}
if (state == 3) {
if (c == ';') {
if (param_count < 15) {
param_count++;
}
return;
} else if (c >= '0' && c <= '9') {
if (!param_count) param_count = 1;
params[param_count-1] = params[param_count-1] * 10 + (c - '0');
return;
} else {
state = 4;
}
}
if (state == 4) {
switch (c) {
case 'H':
case 'f':
if (params[0]) params[0]--;
if (params[1]) params[1]--;
goto_xy(params[0], params[1]);
state = 0;
break;
case 'A':
if (param_count > 0) {
goto_xy(term_x, term_y - params[0]);
} else {
goto_xy(term_x, term_y - 1);
}
state = 0;
break;
case 'B':
if (param_count > 0) {
goto_xy(term_x, term_y + params[0]);
} else {
goto_xy(term_x, term_y + 1);
}
state = 0;
break;
case 'C':
if (param_count > 0) {
goto_xy(term_x + params[0], term_y);
} else {
goto_xy(term_x + 1, term_y);
}
state = 0;
break;
case 'D':
if (param_count > 0) {
goto_xy(term_x - params[0], term_y);
} else {
goto_xy(term_x - 1, term_y);
}
state = 0;
break;
case 's':
saved_x = term_x;
saved_y = term_y;
state = 0;
break;
case 'u':
goto_xy(saved_x, saved_y);
state = 0;
break;
case '7':
saved_x = term_x;
saved_y = term_y;
saved_attr = attrib;
state = 0;
break;
case '8':
goto_xy(saved_x, saved_y);
attrib = saved_attr;
break;
case 'm':
for (j=0;j<param_count;j++) {
switch (params[j]) {
case 0:
attrib = 0x07;
break;
case 1:
bold = 1;
break;
case 2:
bold = 0;
break;
case 30:
attrib &= 0xF0;
if (bold) {
attrib |= 0x08;
} else {
attrib |= 0x00;
}
break;
case 31:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0C;
} else {
attrib |= 0x04;
}
break;
case 32:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0A;
} else {
attrib |= 0x02;
}
break;
case 33:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0E;
} else {
attrib |= 0x06;
}
break;
case 34:
attrib &= 0xF0;
if (bold) {
attrib |= 0x09;
} else {
attrib |= 0x01;
}
break;
case 35:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0D;
} else {
attrib |= 0x05;
}
break;
case 36:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0B;
} else {
attrib |= 0x03;
}
break;
case 37:
attrib &= 0xF0;
if (bold) {
attrib |= 0x0F;
} else {
attrib |= 0x07;
}
break;
case 40:
attrib &= 0x0F;
attrib |= 0x00;
break;
case 41:
attrib &= 0x0F;
attrib |= 0x40;
break;
case 42:
attrib &= 0x0F;
attrib |= 0x20;
break;
case 43:
attrib &= 0x0F;
attrib |= 0x60;
break;
case 44:
attrib &= 0x0F;
attrib |= 0x10;
break;
case 45:
attrib &= 0x0F;
attrib |= 0x50;
break;
case 46:
attrib &= 0x0F;
attrib |= 0x30;
break;
case 47:
attrib &= 0x0F;
attrib |= 0x70;
break;
}
}
state = 0;
break;
case 'K':
if (params[0] == 0) {
j = term_x;
for (k=j;k<char_width;k++) {
draw_char(k * (int)bmapfont.Width, term_y * (int)bmapfont.Height, ' ');
}
update_cursor(1);
term_x = j;
} else if (params[0] == 1) {
j = term_x;
term_x = 0;
for (k=0;k<j;j++) {
draw_char(k * (int)bmapfont.Width, term_y * (int)bmapfont.Height, ' ');
}
update_cursor(1);
term_x = j;
} else if (params[0] == 2) {
j = term_x;
for (k=0;k<char_width;k++) {
draw_char(k * (int)bmapfont.Width, term_y * (int)bmapfont.Height, ' ');
}
update_cursor(1);
term_x = j;
}
state = 0;
break;
case 'J':
if (params[0] == 0) {
quinn_fill_rect(window_handle, surface, term_w, term_h, 0, term_y * bmapfont.Height, term_w, (char_height - term_y )* bmapfont.Height, console_col_map[attrib & 0xF0 >> 4]);
} else if (params[0] == 1) {
quinn_fill_rect(window_handle, surface, term_w, term_h, 0, 0, term_w, term_y * bmapfont.Height, console_col_map[attrib & 0xF0 >> 4]);
} else if (params[0] == 2) {
clear_screen();
term_x = 0;
term_y = 0;
}
update_cursor(1);
state = 0;
break;
case 'h':
if (params[0] == 12) {
echo = 0;
}
state = 0;
break;
case 'i':
if (params[0] == 12) {
echo = 1;
}
state = 0;
break;
default:
state = 0;
break;
}
}
}
void exit_callback(int wh) {
quinn_exit();
exit(0);
}
void input_char(char c) {
write(ParentWrite, &c, 1);
if (echo) {
process_char(c);
}
}
char *sargv[] = {"shell.exe", NULL};
int main(int argc, char **argv) {
struct window_req_t *req;
char buffer[512];
int len;
int i;
int cpid;
unsigned char *icon;
struct widget_t *surf;
attrib = 0x07;
if (pipe(read_pipe) == -1) {
exit(-1);
}
if (pipe(write_pipe) == -1) {
exit(-1);
}
cpid = fork();
if (cpid == -1) {
exit(-1);
}
if (cpid == 0) {
close(0);
dup(ChildRead);
close(ChildRead);
close(1);
dup(ChildWrite);
close(ChildWrite);
close(ParentRead);
close(ParentWrite);
execve("disk0:/shell.exe", sargv, environ);
exit(-1);
} else {
close(ChildRead);
close(ChildWrite);
term_w = 640;
term_h = 400;
char_height = 25;//height / font.Height;
char_width = 80;//width / font.Width;
quinn_init();
req = (struct window_req_t *)malloc(sizeof(struct window_req_t));
convert_xpm(terminal_xpm, &icon);
req->x = 30;
req->y = 30;
req->width = 640;
req->height = 400;
req->icon = icon;
req->flags = 0;
strcpy(req->name, "Terminal");
window_handle = quinn_req_window(req, exit_callback);
free(req);
free(icon);
term_x = 0;
term_y = 0;
surf = quinn_add_surface(window_handle, 0, 0, term_w, term_h, NULL, input_char, NULL);
quinn_surface_set_cooked(surf, 1);
surface = quinn_surface_get_surface(surf);
quinn_fill_rect(window_handle, surface, 640, 400, 0, 0, 640,400, 0xff000000);
cursor_save_buffer = (char *)malloc(8 * 4 * 4);
cursor_save_x = -1;
cursor_save_y = -1;
while (1) {
len = 0;
__asm__ volatile ("int $0x30" : "=a" (len) : "0" (5), "b" (ParentRead), "c" (buffer), "d" (512));
if (len == 0) {
quinn_exit();
exit(0);
}
if (len > 0) {
for(i=0;i<len;i++) {
process_char(buffer[i]);
}
}
quinn_process();
quinn_yield();
}
}
}