575 lines
12 KiB
C
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();
|
|
}
|
|
}
|
|
}
|