/* コンソール関係 */

#include "bootpack.h"
//#include "GT3D.h"
#include <stdio.h>
#include <string.h>

int memf = 0;

extern unsigned int mdata[3];
extern char cpath[256];
extern char epath[1024];
extern struct SHEET *sht_back;
extern struct TIMERCTL timerctl;

void keywin_off(struct SHEET *key_win);
void keywin_on(struct SHEET *key_win);

void dir_cons(struct CONSOLE *cons, struct FILEINFO *finfo);
int hrb_api_fwrite(char *sbuf, int size, struct FILEHANDLE *fh, int *fat);
int strtol(char *s, char **endp, int base);	/* 標準関数（stdlib.h） */

unsigned char t[7];
char prompt[256];

void console_task(struct SHEET *sheet, int memtotal)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	struct TASK *task = task_now();
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	int i, *fat = (int *) memman_alloc_4k(memman, 4 * 2880);
	struct CONSOLE cons;
	struct FILEHANDLE fhandle[8];
	char cmdline[4096];
	unsigned char *sjis = (char *) *((int *) 0x0fe8);

	cons.sht = sheet;
	cons.cur_x =  8;
	cons.cur_y = 28;
	cons.cur_c = -1;
	task->cons = &cons;
	task->cmdline = cmdline;
	
	struct CHUNK_STACK *stack = stack_alloc();
	stack_init(stack);
	
	struct CHUNK_STACK *stack2 = stack_alloc();
	stack_init(stack2);

	if (cons.sht != 0) {
		cons.timer = timer_alloc();
		timer_init(cons.timer, &task->fifo, 1);
		timer_settime(cons.timer, 50);
	}
	file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200));
	for (i = 0; i < 8; i++) {
		fhandle[i].buf = 0;	/* 未使用マーク */
	}
	task->fhandle = fhandle;
	task->fat = fat;
	if (sjis[4096] != 0xff) {	/* 日本語フォントファイルを読み込めたか？ */
		task->langmode = 1;
	} else {
		task->langmode = 0;
	}

	task->langbyte1 = 0x00;
	
	stack_push(stack," ");

	/* プロンプト表示 */
	sprintf(prompt, "[root@tuOS %s]# ", cpath);
	cons_putstr0(&cons, prompt);

	for (;;) {
		io_cli();
		if (fifo32_status(&task->fifo) == 0) {
			task_sleep(task);
			io_sti();
		} else {
			i = fifo32_get(&task->fifo);
			io_sti();
			if (i <= 1 && cons.sht != 0) { /* カーソル用タイマ */
				if (i != 0) {
					timer_init(cons.timer, &task->fifo, 0); /* 次は0を */
					if (cons.cur_c >= 0) {
						cons.cur_c = COL8_FFFFFF;
					}
				} else {
					timer_init(cons.timer, &task->fifo, 1); /* 次は1を */
					if (cons.cur_c >= 0) {
						cons.cur_c = COL8_000000;
					}
				}
				timer_settime(cons.timer, 50);
			}
			if (i == 2) {	/* カーソルON */
				cons.cur_c = COL8_FFFFFF;
			}
			if (i == 3) {	/* カーソルOFF */
				if (cons.sht != 0) {
					boxfill8(cons.sht->buf, cons.sht->bxsize, COL8_000000,
						cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15);
				}
				cons.cur_c = -1;
			}
			if (i == 4) {	/* コンソールの「×」ボタンクリック */
				cmd_exit(&cons, fat);
			}
			if (256 <= i && i <= 511) { /* キーボードデータ（タスクA経由） */
				if (i == 8 + 256) {
					/* バックスペース */
					if (cons.cur_x > 8 + (strlen(prompt) * 8)) {
						/* カーソルをスペースで消してから、カーソルを1つ戻す */
						cons_putchar(&cons, ' ', 0);
						cons.cur_x -= 8;
						cons_putchar(&cons, ' ', 0);
					}
				} else if (i == 10 + 256) {
					/* Enter */
					/* カーソルをスペースで消してから改行する */
					cons_putchar(&cons, ' ', 0);
					cmdline[cons.cur_x / 8 - (strlen(prompt) + 1)] = 0;
					cons_newline(&cons);
					stack_push(stack, cmdline);
					cons_runcmd(cmdline, &cons, fat, memtotal);	/* コマンド実行 */
					strcpy(cmdline,"");
					if (cons.sht == 0) {
						cmd_exit(&cons, fat);
					}
					/* プロンプト表示 */
					cons_putstr0(&cons, prompt);
				} else if(i == CUR_UP + 256) {
					cons.cur_x = 8 + (strlen(prompt) * 8);
					stack_push(stack2,cmdline);
					for(i = 0;i < strlen(cmdline) + 1; i++) {
						cons_putchar(&cons, ' ', 1);
					}
					cons_putchar(&cons, ' ', 0);
					char *stacktmp = stack_pop(stack);
					strcpy(cmdline,stacktmp);
					if(stack->sp == 0) stack_pop(stack2);
					cons.cur_x = 8 + (strlen(prompt) * 8);
					for(i = 0;i < strlen(cmdline); i++) {
						cons_putchar(&cons, cmdline[i], 1);
					}
				} else if(i == CUR_DOWN + 256) {
					cons.cur_x = 8 + (strlen(prompt) * 8);
					stack_push(stack,cmdline);
					for(i = 0;i < strlen(cmdline) + 1; i++) {
						cons_putchar(&cons, ' ', 1);
					}
					cons_putchar(&cons, ' ', 0);
					if(stack2->sp == 0) stack_pop(stack);
					char *stacktmp = stack_pop(stack2);
					strcpy(cmdline,stacktmp);
					cons.cur_x = 8 + (strlen(prompt) * 8);
					for(i = 0;i < strlen(cmdline); i++) {
						cons_putchar(&cons, cmdline[i], 1);
					}
				} else if(i == CUR_LEFT + 256 || i == CUR_RIGHT + 256) {
					
				} else {
					/* 一般文字 */
					if (cons.cur_x < 624 && i != 1 + 256) {
						/* 一文字表示してから、カーソルを1つ進める */
						cmdline[cons.cur_x / 8 - (strlen(prompt) + 1)] = i - 256;
						cons_putchar(&cons, i - 256, 1);
					}
				}
			}
			
			/* カーソル再表示 */
			if (cons.sht != 0) {
				if (cons.cur_c >= 0) {
					boxfill8(cons.sht->buf, cons.sht->bxsize, cons.cur_c, 
						cons.cur_x, cons.cur_y + 14, cons.cur_x + 7, cons.cur_y + 15);
				}
				sheet_refresh(cons.sht, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16);
			}
		}
	}
}

void cons_putchar(struct CONSOLE *cons, int chr, char move)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	char s[2];
	s[0] = chr;
	s[1] = 0;
	if (s[0] == 0x09) {	/* タブ */
		for (;;) {
			if (cons->sht != 0) {
				putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1);
			}
			cons->cur_x += 8;
			if(binfo->scrnx >= 640 && binfo->scrny >= 480) {
				if (cons->cur_x == 8 + 624) {
					cons_newline(cons);
				}
			} else {
				if (cons->cur_x == 8 + 240) {
					cons_newline(cons);
				}
			}
			if (((cons->cur_x - 8) & 0x1f) == 0) {
				break;	/* 32で割り切れたらbreak */
			}
		}
	} else if (s[0] == 0x0a) {	/* 改行 */
		cons_newline(cons);
	} else if (s[0] == 0x0d) {	/* 復帰 */
		/* とりあえずなにもしない */
	} else {	/* 普通の文字 */
		if (cons->sht != 0) {
			putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1);
		}
		if (move != 0) {
			/* moveが0のときはカーソルを進めない */
			cons->cur_x += 8;
			if(binfo->scrnx >= 640 && binfo->scrny >= 480) {
				if (cons->cur_x == 8 + 624) {
					cons_newline(cons);
				}
			} else {
				if (cons->cur_x == 8 + 240) {
					cons_newline(cons);
				}
			}
		}
	}
	return;
}

void cons_newline(struct CONSOLE *cons)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	int x, y;
	struct SHEET *sheet = cons->sht;
	struct TASK *task = task_now();
	if(binfo->scrnx >= 640 && binfo->scrny >= 480) {
		if (cons->cur_y < 28 + 416) {
			cons->cur_y += 16; /* 次の行へ */
		} else {
			/* スクロール */
			if (sheet != 0) {
				for (y = 28; y < 28 + 428; y++) {
					for (x = 8; x < 8 + 624; x++) {
						sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize];
					}
				}
				for (y = 28 + 428; y < 28 + 444; y++) {
					for (x = 8; x < 8 + 624; x++) {
						sheet->buf[x + y * sheet->bxsize] = COL8_000000;
					}
				}
				sheet_refresh(sheet, 8, 28, 8 + (640 - 16), 28 + (480 - 20 - 16));
			}
		}
	} else {
		if (cons->cur_y < 28 + 112) {
			cons->cur_y += 16; /* 次の行へ */
		} else {
			/* スクロール */
			if (sheet != 0) {
				for (y = 28; y < 28 + 112; y++) {
					for (x = 8; x < 8 + 240; x++) {
						sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize];
					}
				}
				for (y = 28 + 112; y < 28 + 128; y++) {
					for (x = 8; x < 8 + 240; x++) {
						sheet->buf[x + y * sheet->bxsize] = COL8_000000;
					}
				}
				sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
			}
		}
	}
	cons->cur_x = 8;
	if (task->langmode == 1 && task->langbyte1 != 0) {
		cons->cur_x = 16;
	}
	return;
}

void cons_putstr0(struct CONSOLE *cons, char *s)
{
	for (; *s != 0; s++) {
		cons_putchar(cons, *s, 1);
	}
	return;
}

void cons_putstr1(struct CONSOLE *cons, char *s, int l)
{
	int i;
	for (i = 0; i < l; i++) {
		cons_putchar(cons, s[i], 1);
	}
	return;
}

char *cons_getstring(char *work, char *typestr, ...)
{
	va_list lst;
	va_start(lst, typestr);

	vsprintf(work,typestr,lst);

	va_end(lst);

	return work;
}

void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, int memtotal)
{
	struct TASK *task = task_now();
	char work[256];
	
	if (strcmp(cmdline, "free") == 0 && cons->sht != 0) {
		cmd_mem(cons, memtotal);
	} else if (strcmp(cmdline, "clear") == 0 && cons->sht != 0) {
		cmd_cls(cons);
	} else if (strcmp(cmdline, "ls") == 0 && cons->sht != 0) {
		cmd_dir(cons, fat);
	} else if (strcmp(cmdline, "exit") == 0) {
		cmd_exit(cons, fat);
	} else if (strncmp(cmdline, "sh -ncst ", 9) == 0) {
		cmd_ncst(cons, cmdline, memtotal);
	} else if (strncmp(cmdline, "sh ", 3) == 0) {
		cmd_start(cons, cmdline, memtotal);
	} else if (strncmp(cmdline, "chcp ", 5) == 0) {
		cmd_langmode(cons, cmdline);
	} else if (strncmp(cmdline, "ren ", 4) == 0) {
		cmd_rem(cons, cmdline);
	} else if (strncmp(cmdline, "rm ", 3) == 0) {
		cmd_del(cons, cmdline);
	} else if (strncmp(cmdline, "cd ", 3) == 0) {
		cmd_cd(cons, cmdline, fat);
	} else if (cmdline[0] != 0 && cmdline[0] != ' ') {
		if (cmd_app(cons, fat, cmdline, 0) == 0 && memf == 0) {
			/* コマンドではなく、アプリでもなく、さらに空行でもない */
			if(task->langmode == 0) {
				cons_putstr0(cons, cons_getstring(work, "Unknown Command : %s\n\n", cmdline));
			} else if(task->langmode == 1) {
				cons_putstr0(cons, cons_getstring(work, "不明なコマンド : %s\n\n", cmdline));
			}
		}
	}
	return;
}

void cmd_mem(struct CONSOLE *cons, int memtotal)
{
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	struct TASK *task = task_now();
	char s[60];
	if(task->langmode == 0) {
		sprintf(s, "total   %dMB\nfree %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024);
	} else if(task->langmode == 1) {
		sprintf(s, "トータル   %dMB\nフリー %dKB\n\n", memtotal / (1024 * 1024), memman_total(memman) / 1024);
	}
	cons_putstr0(cons, s);
	return;
}

void cmd_cls(struct CONSOLE *cons)
{
	int x, y;
	struct SHEET *sheet = cons->sht;
	for (y = 28; y < 28 + 128; y++) {
		for (x = 8; x < 8 + 240; x++) {
			sheet->buf[x + y * sheet->bxsize] = COL8_000000;
		}
	}
	sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
	cons->cur_y = 28;
	return;
}

void cmd_dir(struct CONSOLE *cons, int *fat)
{
	int i, rde = 0;
	int clustno, nextno;
	struct FILEINFO *ffinfo, dfinfo[16];

	if (strcmp(cpath, "/") == 0) {
		ffinfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600);
		rde = 1;
	} else {
		ffinfo = file_search2(cpath, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, fat);
		if (ffinfo == 0 || (ffinfo->type & 0x10) != 0x10) {
			return;
		}
		if (ffinfo->clustno == 0x0000) {
			rde = 1;
		}
	}

	if (rde == 1) {
		for (i = 0; i < 224; i++) {
			if (ffinfo[i].name[0] == 0x00) {
				break;
			}
			dir_cons(cons, &ffinfo[i]);
		}
	} else {
		nextno = ffinfo->clustno;
		for (i = 0; i < MAX_ENTRY; i++) {
			if ((i % 16) == 0) {
				if (nextno >= 0x0ff7) {
					break;
				}
				clustno = nextno;
				file_loadfile(clustno, 512, (char *) dfinfo,
							  fat, (char *) (ADR_DISKIMG + 0x003e00));
				nextno = fat[clustno];
			}
			if (dfinfo[i % 16].name[0] == 0x00) {
				break;
			}
			dir_cons(cons, &dfinfo[i % 16]);
		}
	}
	cons_newline(cons);

	return;
}

void dir_cons(struct CONSOLE *cons, struct FILEINFO *finfo)
{
	int i;
	char s[30];
	memset(s, 0, sizeof(s));
	if (finfo->name[0] != 0xe5) {
		if ((finfo->type & 0x18) == 0) {
			sprintf(s, "filename.ext   %7d\n", finfo->size);
			for (i = 0; i < 8; i++) {
				s[i] = finfo->name[i];
			}
			s[ 9] = finfo->ext[0];
			s[10] = finfo->ext[1];
			s[11] = finfo->ext[2];
		} else if ((finfo->type & 0x10) == 0x10) {
			sprintf(s, "dir0name       <DIR>  \n");
			for (i = 0; i < 8; i++) {
				s[i] = finfo->name[i];
			}
		}
		cons_putstr0(cons, s);
	}
	return;
}

void dir_cons_str(char *s, struct FILEINFO *finfo);

void cmd_dir_str(char *s, int ind, int *fat)
{
	int i, rde = 0;
	int clustno, nextno;
	struct FILEINFO *ffinfo, dfinfo[16];

	if (strcmp(cpath, "/") == 0) {
		ffinfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600);
		rde = 1;
	} else {
		ffinfo = file_search2(cpath, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, fat);
		if (ffinfo == 0 || (ffinfo->type & 0x10) != 0x10) {
			return;
		}
		if (ffinfo->clustno == 0x0000) {
			rde = 1;
		}
	}

	i = ind;

	if (rde == 1) {
		if (ffinfo[i].name[0] == 0x00) {
			*s = 0;
			return;
		}
		dir_cons_str(s, &ffinfo[i]);
	} else {
		nextno = ffinfo->clustno;
		if ((i % 16) == 0) {
			if (nextno >= 0x0ff7) {
				*s = 0;
				return;
			}
			clustno = nextno;
			file_loadfile(clustno, 512, (char *) dfinfo,
						  fat, (char *) (ADR_DISKIMG + 0x003e00));
			nextno = fat[clustno];
		}
		if (dfinfo[i % 16].name[0] == 0x00) {
			*s = 0;
			return;
		}
		dir_cons_str(s, &dfinfo[i % 16]);
	}

	return;
}

void dir_cons_str(char *s, struct FILEINFO *finfo)
{
	int i;
	memset(s, 0, sizeof(s));
	if (finfo->name[0] != 0xe5) {
		if ((finfo->type & 0x18) == 0) {
			sprintf(s, "filename.ext   %7d\n", finfo->size);
			for (i = 0; i < 8; i++) {
				s[i] = finfo->name[i];
			}
			s[ 9] = finfo->ext[0];
			s[10] = finfo->ext[1];
			s[11] = finfo->ext[2];
		} else if ((finfo->type & 0x10) == 0x10) {
			sprintf(s, "dir0name       <DIR>  \n");
			for (i = 0; i < 8; i++) {
				s[i] = finfo->name[i];
			}
		}
	}
	return;
}

void cmd_exit(struct CONSOLE *cons, int *fat)
{
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	struct TASK *task = task_now();
	struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
	struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec);
	if (cons->sht != 0) {
		timer_cancel(cons->timer);
	}
	memman_free_4k(memman, (int) fat, 4 * 2880);
	io_cli();
	if (cons->sht != 0) {
		fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768);	/* 768〜1023 */
	} else {
		fifo32_put(fifo, task - taskctl->tasks0 + 1024);	/* 1024〜2023 */
	}
	io_sti();
	for (;;) {
		task_sleep(task);
	}
}

void cmd_start(struct CONSOLE *cons, char *cmdline, int memtotal)
{
	struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
	struct SHEET *sht = open_console(shtctl, memtotal);
	struct FIFO32 *fifo = &sht->task->fifo;
	int i;
	sheet_slide(sht, 32, 4);
	sheet_updown(sht, shtctl->top);
	/* コマンドラインに入力された文字列を、一文字ずつ新しいコンソールに入力 */
	for (i = 3; cmdline[i] != 0; i++) {
		fifo32_put(fifo, cmdline[i] + 256);
	}
	fifo32_put(fifo, 10 + 256);	/* Enter */
	cons_newline(cons);
	return;
}

void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal)
{
	struct TASK *task = open_constask(0, memtotal);
	struct FIFO32 *fifo = &task->fifo;
	int i;
	/* コマンドラインに入力された文字列を、一文字ずつ新しいコンソールに入力 */
	for (i = 9; cmdline[i] != 0; i++) {
		fifo32_put(fifo, cmdline[i] + 256);
	}
	fifo32_put(fifo, 10 + 256);	/* Enter */
	cons_newline(cons);
	return;
}

void cmd_langmode(struct CONSOLE *cons, char *cmdline)
{
	struct TASK *task = task_now();
	char *p = cmdline + 5;
	unsigned int mode = strtol(p, &p, 10);
	if (mode == 437) {
		task->langmode = 0;
		cons_putstr0(cons, "code page is 437(English)\n");
	} else if (mode == 932) {
		task->langmode = 1;
		cons_putstr0(cons, "現在のコードページは 932(日本語) です。\n");
	} else {
		cons_putstr0(cons, "code page number error\n");
	}
	cons_newline(cons);
	return;
}

void cmd_rem(struct CONSOLE *cons, char *cmdline)
{
	struct FILEINFO *finfo;
	struct TASK *task = task_now();
	char *p;
	char s1[30];
	char s2[30];
	char s3[30];

	for (p = cmdline + 4; *p > ' '; p++) { }
	*p = 0;
	for (; *p == ' '; p++) { }

	finfo = file_search(cmdline + 4, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);

	if(finfo == 0) {
		if(task->langmode == 0) {
			cons_putstr0(cons, "File not found");
		} else if(task->langmode == 1) {
			cons_putstr0(cons, "ファイルが見つかりません。");
		}
		cons_newline(cons);
		return;
	}

	for (p = cmdline + 4; *p > ' '; p++) { }
	for (; *p == 0; p++) { }
	
	if(task->langmode == 0) {
		sprintf(s1,"Older name:%s",cmdline + 4);
	} else if(task->langmode == 1) {
		sprintf(s1,"古いファイル名:%s",cmdline + 4);
	}
	cons_putstr0(cons, s1);
	cons_newline(cons);

	if(task->langmode == 0) {
		sprintf(s2,"New name:%s",p);
	} else if(task->langmode == 1) {
		sprintf(s2,"新しいファイル名:%s",p);
	}
	cons_putstr0(cons, s2);
	cons_newline(cons);

	sprintf(s3,"Fileinfo:0x%016X",finfo);
	cons_putstr0(cons, s3);
	cons_newline(cons);

	int i = 0;
	int j = 0;

	strcpy(finfo->name, "        ");
	strcpy(finfo->ext, "   ");

	while(p[i] != '.') {
		if(p[i] >= 'a' && p[i] <= 'z') p[i] -= 0x20;
		finfo->name[i] = p[i];
		i++;
	}

	i++;

	while(p[i] != 0x00) {
		if(p[i] >= 'a' && p[i] <= 'z') p[i] -= 0x20;
		finfo->ext[j] = p[i];
		i++;
		j++;
	}
}

void cmd_del(struct CONSOLE *cons, char *cmdline)
{
	struct FILEINFO *finfo;
	struct TASK *task = task_now();
	
	finfo = file_search2(cmdline + 4, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, task->fat);
	if (finfo == 0 || (finfo->type & 0x18) != 0) {
		return;
	}
	file_clearfat(task->fat, finfo->clustno);
	file_move(0, finfo);
}

void cmd_cd(struct CONSOLE *cons, char *cmdline, int *fat)
{
	char fpath[256];
	struct FILEINFO *ffinfo;
	struct TASK *task = task_now();

	file_path(fpath, cmdline + 3, sizeof(fpath));
	if (fpath[0] == 0) {
		if(task->langmode == 0) {
			cons_putstr0(cons, "No such directory.\n\n");
		} else if(task->langmode == 1) {
			cons_putstr0(cons, "そのようなディレクトリはありません。\n\n");
		}
		return;
	}

	if (strcmp(fpath, "/") == 0) {
		memset(cpath, 0, sizeof(cpath));
		cpath[0] = '/';
	} else {
		ffinfo = file_search2(fpath, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, fat);
		if (ffinfo != 0 && (ffinfo->type & 0x10) == 0x10) {
			memset(cpath, 0, sizeof(cpath));
			strcpy(cpath, fpath);
			if (cpath[strlen(cpath) - 1] != '/') {
				cpath[strlen(cpath)] = '/';
			}
		} else {
			if(task->langmode == 0) {
			cons_putstr0(cons, "No such directory.\n\n");
			} else if(task->langmode == 1) {
				cons_putstr0(cons, "そのようなディレクトリはありません。\n\n");
			}
		}
	}
	
	sprintf(prompt, "[root@tuOS %s]# ", cpath);

	return;
}

int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline, int sysf)
{
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	struct FILEINFO *finfo;
	char name[18], *p, *q;
	struct TASK *task = task_now();
	int i, segsiz, datsiz, esp, dathrb, appsiz;
	struct SHTCTL *shtctl;
	struct SHEET *sht;
	int point = 0;

	/* コマンドラインからファイル名を生成 */
	for (i = 0; i < 13; i++) {
		if (cmdline[i] <= ' ') {
			break;
		}
		name[i] = cmdline[i];
	}
	name[i] = 0; /* とりあえずファイル名の後ろを0にする */

	/* ファイルを探す */
	finfo = file_search2(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, fat);
	if (finfo == 0 && name[i - 1] != '.') {
			name[i    ] = '.';
			name[i + 1] = 'H';
			name[i + 2] = 'R';
			name[i + 3] = 'B';
			name[i + 4] = 0;
			finfo = file_search2(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, fat);
		
		if(finfo == 0 && name[i - 1] != '.')
		{
			/* 見つからなかったので後ろに".EHR"をつけてもう一度探してみる */
			name[i    ] = '.';
			name[i + 1] = 'E';
			name[i + 2] = 'H';
			name[i + 3] = 'R';
			name[i + 4] = 0;
			finfo = file_search2(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, fat);
		}
	}

	if (finfo != 0) {
		/* ファイルが見つかった場合 */
		appsiz = finfo->size;
		p = file_loadfile2(finfo->clustno, &appsiz, fat);
		if (appsiz >= 36 && (strncmp(p + 4, "Hari", 4) == 0 || strncmp(p + 4, "Ehr3", 4) == 0) && *p == 0x00) {
			segsiz = *((int *) (p + 0x0000));
			esp    = *((int *) (p + 0x000c));
			datsiz = *((int *) (p + 0x0010));
			dathrb = *((int *) (p + 0x0014));
			q = (char *) memman_alloc_4k(memman, segsiz);
			task->ds_base = (int) q;
			while(point <= 8)
			{
				if(name[point] <= 'z' && name[point] >= 'a') name[point] -= 0x20;
				point++;
			}
			strcpy(task->taskname, name);
			set_segmdesc(task->ldt + 0, appsiz + 1024 - 1, (int) p, AR_CODE32_ER + 0x60);
			set_segmdesc(task->ldt + 1, segsiz + 1024 - 1, (int) q, AR_DATA32_RW + 0x60);
			for (i = 0; i < datsiz; i++) {
				q[esp + i] = p[dathrb + i];
			}
			task->appf = 1;
			start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0));
			task->appf = 0;
			shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
			for (i = 0; i < MAX_SHEETS; i++) {
				sht = &(shtctl->sheets0[i]);
				if ((sht->flags & 0x11) == 0x11 && sht->task == task) {
					/* アプリが開きっぱなしにした下じきを発見 */
					sheet_free(sht);	/* 閉じる */
				}
			}
			for (i = 0; i < 8; i++) {	/* クローズしてないファイルをクローズ */
				if (task->fhandle[i].buf != 0) {
					memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size);
					task->fhandle[i].buf = 0;
				}
			}
			timer_cancelall(&task->fifo);
			memman_free_4k(memman, (int) q, segsiz);
			task->langbyte1 = 0;
		} else {
			if(task->langmode == 0) {
				cons_putstr0(cons, ".hrb(.ehr) file format error\n");
			} else if(task->langmode == 1) {
				cons_putstr0(cons, "実行可能なファイルではありません。\n\n");
			}
		}
		memman_free_4k(memman, (int) p, appsiz);
		cons_newline(cons);
		return 1;
	}
	/* ファイルが見つからなかった場合 */
	return 0;
}

int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
	struct TASK *task = task_now();
	struct TASK *task_cons;
	int ds_base = task->ds_base;
	struct CONSOLE *cons = task->cons;
	struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
	struct SHEET *sht;
	struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0x0fec);
	int *reg = &eax + 1;	/* eaxの次の番地 */
		/* 保存のためのPUSHADを強引に書き換える */
		/* reg[0] : EDI,   reg[1] : ESI,   reg[2] : EBP,   reg[3] : ESP */
		/* reg[4] : EBX,   reg[5] : EDX,   reg[6] : ECX,   reg[7] : EAX */
	int i, j;
	struct FILEINFO *finfo;
	struct FILEHANDLE *fh;
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	int mx;
	int my;
	int cl;
	int slen = 0;
	char *chr;
	struct BUTTON *bt;
	struct BUTTON init_bt;
	unsigned char *p;
	char dir[13];
	int vx, vy;
	int x, y;
	unsigned char *graph;
	char taskname[16];
	unsigned int *winbuf;
	int clustno, nextno;
	struct FILEINFO *ffinfo, dfinfo[256];
	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	//GT3D_screen *scr;
	//model_t *model_p;
	//camera_t *camera;
	//model_t model;

	strcpy(taskname, task->taskname);
	strcpy(task->taskname, "CONSOLE_API");

	if (edx == 1) {
		cons_putchar(cons, eax & 0xff, 1);
	} else if (edx == 2) {
		cons_putstr0(cons, (char *) ebx + ds_base);
	} else if (edx == 3) {
		cons_putstr1(cons, (char *) ebx + ds_base, ecx);
	} else if (edx == 4) {
		if(task->cons->sht->act == 0) keywin_on(task->cons->sht);
		task->cons->sht->act = 1;
		return &(task->tss.esp0);
	} else if (edx == 5) {
		if(task->cons->sht->act == 1) keywin_off(task->cons->sht);
		task->cons->sht->act = 0;
		sht = sheet_alloc(shtctl);
		sht->task = task;
		sht->flags |= 0x10;
		sht->flag2 = 0;
		//winbuf = (unsigned int *) ebx + ds_base;
		sheet_setbuf2(sht, ebx + ds_base, esi, edi, eax);
		make_window8(sht->buf, esi, edi, (char *) ecx + ds_base, 1);
		sheet_slide(sht, ((shtctl->xsize - esi) / 2) & ~3, (shtctl->ysize - edi) / 2);
		sheet_updown(sht, shtctl->top); /* 今のマウスと同じ高さになるように指定： マウスはこの上になる */
		sht->act = 1;
		char debug[30];
		sprintf(debug, "console: \n sht->buf: 0x%08x\n ebx + ds_base: 0x%08x\n vram: 0x%08x\n bpp: %dbpp\n", &(sht->buf[0]), ebx + ds_base, binfo->vram, binfo->vmode);
		cons_putstr0(cons, debug);
		reg[7] = (int) sht;
	} else if (edx == 6) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		putfonts8_asc(sht->buf, sht->bxsize, esi, edi, eax, (char *) ebp + ds_base);
		if ((ebx & 1) == 0) {
			sheet_refresh(sht, esi, edi, esi + ecx * 8, edi + 16);
		}
	} else if (edx == 7) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		boxfill8(sht->buf, sht->bxsize, ebp, eax, ecx, esi, edi);
		if ((ebx & 1) == 0) {
			sheet_refresh(sht, eax, ecx, esi + 1, edi + 1);
		}
	} else if (edx == 8) {
		memman_init((struct MEMMAN *) (ebx + ds_base));
		ecx &= 0xfffffff0;	/* 16バイト単位に */
		memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx);
	} else if (edx == 9) {
		ecx = (ecx + 0x0f) & 0xfffffff0; /* 16バイト単位に切り上げ */
		reg[7] = memman_alloc((struct MEMMAN *) (ebx + ds_base), ecx);
	} else if (edx == 10) {
		ecx = (ecx + 0x0f) & 0xfffffff0; /* 16バイト単位に切り上げ */
		memman_free((struct MEMMAN *) (ebx + ds_base), eax, ecx);
	} else if (edx == 11) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		sht->buf[sht->bxsize * edi + esi] = eax;
		if ((ebx & 1) == 0) {
			sheet_refresh(sht, esi, edi, esi + 1, edi + 1);
		}
	} else if (edx == 12) {
		sht = (struct SHEET *) ebx;
		sheet_refresh(sht, eax, ecx, esi, edi);
	} else if (edx == 13) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		hrb_api_linewin(sht, eax, ecx, esi, edi, ebp);
		if ((ebx & 1) == 0) {
			if (eax > esi) {
				i = eax;
				eax = esi;
				esi = i;
			}
			if (ecx > edi) {
				i = ecx;
				ecx = edi;
				edi = i;
			}
			sheet_refresh(sht, eax, ecx, esi + 1, edi + 1);
		}
	} else if (edx == 14) {
		sheet_free((struct SHEET *) ebx);
	} else if (edx == 15) {
		for (;;) {
			io_cli();
			if (fifo32_status(&task->fifo) == 0) {
				if (eax != 0) {
					task_sleep(task);	/* FIFOが空なので寝て待つ */
				} else {
					io_sti();
					reg[7] = -1;
					return 0;
				}
			}
			i = fifo32_get(&task->fifo);
			io_sti();
			if (i <= 1 && cons->sht != 0) { /* カーソル用タイマ */
				/* アプリ実行中はカーソルが出ないので、いつも次は表示用の1を注文しておく */
				timer_init(cons->timer, &task->fifo, 1); /* 次は1を */
				timer_settime(cons->timer, 50);
			}
			if (i == 2) {	/* カーソルON */
				cons->cur_c = COL8_FFFFFF;
			}
			if (i == 3) {	/* カーソルOFF */
				cons->cur_c = -1;
			}
			if (i == 4) {	/* コンソールだけを閉じる */
				timer_cancel(cons->timer);
				io_cli();
				fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 2024);	/* 2024〜2279 */
				cons->sht = 0;
				io_sti();
			}
			if (i >= 256) { /* キーボードデータ（タスクA経由）など */
				reg[7] = i - 256;
				return 0;
			}
		}
	} else if (edx == 16) {
		reg[7] = (int) timer_alloc();
		((struct TIMER *) reg[7])->flags2 = 1;	/* 自動キャンセル有効 */
	} else if (edx == 17) {
		timer_init((struct TIMER *) ebx, &task->fifo, eax + 256);
	} else if (edx == 18) {
		timer_settime((struct TIMER *) ebx, eax);
	} else if (edx == 19) {
		timer_free((struct TIMER *) ebx);
	} else if (edx == 20) {
		if (eax == 0) {
			i = io_in8(0x61);
			io_out8(0x61, i & 0x0d);
		} else {
			i = 1193180000 / eax;
			io_out8(0x43, 0xb6);
			io_out8(0x42, i & 0xff);
			io_out8(0x42, i >> 8);
			i = io_in8(0x61);
			io_out8(0x61, (i | 0x03) & 0x0f);
		}
	} else if (edx == 21) {
		for (i = 0; i < 8; i++) {
			if (task->fhandle[i].buf == 0) {
				break;
			}
		}
		fh = &task->fhandle[i];
		reg[7] = 0;
		if (i < 8) {
			finfo = file_search2((char *) ebx + ds_base,
					(struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, task->fat);
			if (finfo != 0) {
				reg[7] = (int) fh;
				fh->size = finfo->size;
				fh->pos = 0;
				fh->buf = file_loadfile2(finfo->clustno, &fh->size, task->fat);
				fh->finfo = finfo;
				fh->mode = 0;
			}
		}
	} else if (edx == 22) {
		fh = (struct FILEHANDLE *) eax;
		memman_free_4k(memman, (int) fh->buf, fh->size);
		fh->buf = 0;
	} else if (edx == 23) {
		fh = (struct FILEHANDLE *) eax;
		if (ecx == 0) {
			fh->pos = ebx;
		} else if (ecx == 1) {
			fh->pos += ebx;
		} else if (ecx == 2) {
			fh->pos = fh->size + ebx;
		}
		if (fh->pos < 0) {
			fh->pos = 0;
		}
		if (fh->pos > fh->size) {
			fh->pos = fh->size;
		}
	} else if (edx == 24) {
		fh = (struct FILEHANDLE *) eax;
		if (ecx == 0) {
			reg[7] = fh->size;
		} else if (ecx == 1) {
			reg[7] = fh->pos;
		} else if (ecx == 2) {
			reg[7] = fh->pos - fh->size;
		}
	} else if (edx == 25) {
		fh = (struct FILEHANDLE *) eax;
		for (i = 0; i < ecx; i++) {
			if (fh->pos == fh->size) {
				break;
			}
			*((char *) ebx + ds_base + i) = fh->buf[fh->pos];
			fh->pos++;
		}
		reg[7] = i;
	} else if (edx == 26) {
		i = 0;
		for (;;) {
			*((char *) ebx + ds_base + i) =  task->cmdline[i];
			if (task->cmdline[i] == 0) {
				break;
			}
			if (i >= ecx) {
				break;
			}
			i++;
		}
		reg[7] = i;
	} else if (edx == 27) {
		reg[7] = task->langmode;
	} else if (edx == 28) {
		for (i = 0; i < 8; i++) {
			if (task->fhandle[i].buf == 0) {
				break;
			}
		}
		fh = &task->fhandle[i];
		reg[7] = 0;
		if (i < 8) {
			//finfo = file_create(task->fat, (unsigned char *)ebx + ds_base);
			finfo = file_insert((char *)ebx + ds_base, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, task->fat);
			if (finfo != 0) {
				reg[7] = (int) fh;
				fh->size = finfo->size;
				fh->pos = 0;
				fh->add = finfo->clustno;
				fh->inadd = (int) finfo;
				fh->buf = memman_alloc(memman, 512);
				fh->finfo = finfo;
				fh->mode = 0;
				fh->bcaddr = finfo->clustno;
				fh->baddr = 0;
			}
		}
	} else if (edx == 29) {
		fh = (struct FILEHANDLE *) eax;
		hrb_api_fwrite(ebx + ds_base, ecx, fh, task->fat);
	} else if (edx == 30) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		mx = mdata[0] - sht->vx0;
		reg[7] = mx;
	} else if (edx == 31) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		my = mdata[1] - sht->vy0;
		reg[7] = my;
	} else if (edx == 32) {
		io_cli();
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		init_bt.x0 = eax;
		init_bt.y0 = ecx;
		init_bt.x1 = esi;
		init_bt.y1 = edi;
		strcpy(init_bt.title, (char *) ebp + ds_base);
		boxfill8(sht->buf, sht->bxsize, COL8_000000, init_bt.x0    , init_bt.y0    , init_bt.x1    , init_bt.y1    );
		boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, init_bt.x0    , init_bt.y0    , init_bt.x1 - 1, init_bt.y1 - 1);
		boxfill8(sht->buf, sht->bxsize, COL8_848484, init_bt.x0 + 1, init_bt.y0 + 1, init_bt.x1 - 1, init_bt.y1 - 1);
		boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, init_bt.x0 + 1, init_bt.y0 + 1, init_bt.x1 - 2, init_bt.y1 - 2);
		chr = (char *) ebp + ds_base;
		for(slen = 0;chr[slen] != 0;slen++) {}
		putfonts8_asc(sht->buf, sht->bxsize, ((esi - eax) / 2 - (slen - 1)) + (eax - 8), ((edi - ecx) / 2 - 8) + ecx, COL8_000000, init_bt.title);
		if ((ebx & 1) == 0) {
			sheet_refresh(sht, eax, ecx, esi + 1, edi + 1);
		}
		reg[7] = (int) &init_bt;
		io_sti();
	} else if (edx == 33) {
		io_cli();
		bt = (struct BUTTON *) ebx;
		sht = (struct SHEET *) (ecx & 0xfffffffe);
		mx = mdata[0] - sht->vx0;
		my = mdata[1] - sht->vy0;
		cl = mdata[2];
		if(mx >= bt->x0 && mx <= bt->x1 && my >= bt->y0 && my <= bt->y1 && cl != 0) {
			boxfill8(sht->buf, sht->bxsize, COL8_000000, bt->x0    , bt->y0    , bt->x1    , bt->y1    );
			boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, bt->x0 + 1, bt->y0 + 1, bt->x1    , bt->y1    );
			boxfill8(sht->buf, sht->bxsize, COL8_848484, bt->x0 + 1, bt->y0 + 1, bt->x1 - 1, bt->y1 - 1);
			boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, bt->x0 + 2, bt->y0 + 2, bt->x1 - 1, bt->y1 - 1);
			for(slen = 0;bt->title[slen] != 0;slen++) {}
			putfonts8_asc(sht->buf, sht->bxsize, ((bt->x1 - bt->x0) / 2 - (slen - 1)) + (bt->x0 - 8), ((bt->y1 - bt->y0) / 2 - 8) + bt->y0 + 1, COL8_000000, bt->title);
			reg[7] = 1;
		} else {
			boxfill8(sht->buf, sht->bxsize, COL8_000000, bt->x0    , bt->y0    , bt->x1    , bt->y1    );
			boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, bt->x0    , bt->y0    , bt->x1 - 1, bt->y1 - 1);
			boxfill8(sht->buf, sht->bxsize, COL8_848484, bt->x0 + 1, bt->y0 + 1, bt->x1 - 1, bt->y1 - 1);
			boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, bt->x0 + 1, bt->y0 + 1, bt->x1 - 2, bt->y1 - 2);
			for(slen = 0;bt->title[slen] != 0;slen++) {}
			putfonts8_asc(sht->buf, sht->bxsize, ((bt->x1 - bt->x0) / 2 - (slen - 1)) + (bt->x0 - 8), ((bt->y1 - bt->y0) / 2 - 8) + bt->y0, COL8_000000, bt->title);
			reg[7] = 0;
		}
		if ((ecx & 1) == 0) {
			sheet_refresh(sht, bt->x0, bt->y0, bt->x1 + 1, bt->y1 + 1);
		}
		io_sti();
	} else if (edx == 34) {
		reg[7] = mdata[2];
	} else if (edx == 35) {
		task_cons = open_console(shtctl, *((int *) 0x268000))->task;
		for (p = (unsigned char *) ebx + ds_base; *p != 0; p++) {
			if (*p != 0x0d) {
				fifo32_put_io(&task_cons->fifo, *p + 256);
			}
		}
	} else if (edx == 36) {
		cmd_dir_str(dir, ecx, task->fat);
		
		/*ffinfo = file_search2(cpath, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, task->fat);
		file_loadfile(ffinfo->clustno, 512, (char *) finfo, task->fat, (char *) (ADR_DISKIMG + 0x003e00));
		if (finfo[ecx].name[0] != 0x00) {
			if (finfo[ecx].name[0] != 0xe5) {
				if ((finfo[ecx].type & 0x18) == 0) {
					sprintf(dir, "filename.ext");
					for (j = 0; j < 8; j++) {
						dir[j] = finfo[ecx].name[j];
					}
					dir[ 9] = finfo[ecx].ext[0];
					dir[10] = finfo[ecx].ext[1];
					dir[11] = finfo[ecx].ext[2];
				}
			}
		}*/
		i = 0;
		for (;;) {
			*((char *) ebx + ds_base + i) = dir[i];
			i++;
			if(i >= 12) break;
		}
		*((char *) ebx + ds_base + i) = 0;
	} else if (edx == 39) {
		*((char *) eax + ds_base) = (int) binfo->scrnx;
		*((char *) ecx + ds_base) = (int) binfo->scrny;
		*((char *) ebx + ds_base) = (int) binfo->vmode;
	} else if (edx == 42) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		x = ecx;
		y = esi;
		graph = eax + ds_base;
		for (vy = y; vy < ebp + y; vy++) {
			for (vx = x; vx < edi + x; vx++) {
				if(graph[(vy - y) * edi + (vx - x)] != 0) sht->buf[vy * sht->bxsize + vx] = get_int(graph[(vy - y) * edi + (vx - x)]);
			}
		}
	} else if (edx == 44) {
		finfo = file_search2((char *) ebx + ds_base, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224, task->fat);
		if(finfo != 0) reg[7] = (int) finfo->size;
	} else if (edx == 45) {
		sht = (struct SHEET *) (ebx & 0xfffffffe);
		*((char *) ecx + ds_base) = (int) sht->bxsize;
		*((char *) eax + ds_base) = (int) sht->bysize;
	} else if (edx == 46) {
		
	}
	
	strcpy(task->taskname, taskname);
	
	return 0;
}

/*
	下記２関数(inthandler0c, inthandler0d)は z_tools付属のqemuではおかしな動きをします
	ですがVirtualBoxで正常に動作することが確認できています
	おそらくqemuのバグかと思われます
*/

int *inthandler0c(int *esp)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	struct TASK *task = task_now();
	struct CONSOLE *cons = task->cons;
	char s[256];
	if(task->appf == 1) {
		cons_putstr0(cons, "\nProcess Killed  Code-(0x0000000C) :\n STACK_EXCEPTION\n");
		sprintf(s, "%s(0x%08X)\n", task->taskname, esp[11]);
		cons_putstr0(cons, s);
	} else {
		io_cli();
		if(task->langmode == 0) {
			sprintf(s, " STOP (0x0000000C)\n\n STACK_EXCEPTION\n\n System stack is overflowing. System is halted.\n\n %s(0x%08X)\n", task->taskname, esp[11]);
		} else if(task->langmode == 1) {
			sprintf(s, " STOP (0x0000000C)\n\n STACK_EXCEPTION\n\n システムスタックがオーバフローしました。システムは停止しました。\n データ消えてごめんだお(´；ω；｀)\n\n %s(0x%08X)\n", task->taskname, esp[11]);
		}
		boxfill8(sht_back->buf, binfo->scrnx, COL8_000084, 0, 0, binfo->scrnx, binfo->scrny);
		putfonts8_asc(sht_back->buf, binfo->scrnx, 8, 8, COL8_FFFFFF, s);
		sheet_updown(sht_back, 0);
		for(;;) {}
	}
	return &(task->tss.esp0);	/* 異常終了させる */
}

int *inthandler0d(int *esp)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
	struct TASK *task = task_now();
	struct CONSOLE *cons = task->cons;
	char s[256];
	if(task->appf == 1) {
		cons_putstr0(cons, "\nProcess Killed  Code-(0x0000000D) :\n GENERAL_PROTECTED_EXCEPTION\n");
		sprintf(s, "%s(0x%08X)\n", task->taskname, esp[11]);
		cons_putstr0(cons, s);
	} else {
		io_cli();
		if(task->langmode == 0) {
			sprintf(s, " STOP (0x0000000D)\n\n GENERAL_PROTECTED_EXCEPTION\n\n General protected exception is happend. System is halted.\n\n %s(0x%08X)\n", task->taskname, esp[11]);
		} else if(task->langmode == 1) {
			sprintf(s, " STOP (0x0000000D)\n\n GENERAL_PROTECTED_EXCEPTION\n\n 一般保護例外が発生しました。システムは停止しました。\n データ消えてごめんだお(´；ω；｀)\n\n %s(0x%08X)\n", task->taskname, esp[11]);
		}
		boxfill8(sht_back->buf, binfo->scrnx, COL8_000084, 0, 0, binfo->scrnx, binfo->scrny);
		putfonts8_asc(sht_back->buf, binfo->scrnx, 8, 8, COL8_FFFFFF, s);
		sheet_updown(sht_back, 0);
		for(;;) {}
	}
	return &(task->tss.esp0);	/* 異常終了させる */
}

int hrb_api_fwrite(char *sbuf, int size, struct FILEHANDLE *fh, int *fat)
{
	int dsize, wsize = 0, usize = 4096;

	for (; usize == 4096;) {
		if (fh->bpos + size < 4096) {
			memcpy(fh->buf + fh->bpos, sbuf, size);
			fh->pos  += size;
			fh->bpos += size;
			wsize    += size;
			break;
		}
		dsize = 4096 - fh->bpos;
		memcpy(fh->buf + fh->bpos, sbuf, dsize);
		usize = file_savefile(fh, 4096, fat, (char *) (ADR_DISKIMG + 0x003e00));
		size     -= dsize;
		sbuf     += dsize;
		fh->pos  += dsize;
		wsize    += (usize - fh->bpos);
		fh->bpos  = 0;
	}

	return (wsize);
}

void hrb_api_linewin(struct SHEET *sht, int x0, int y0, int x1, int y1, int col)
{
	int i, x, y, len, dx, dy;

	dx = x1 - x0;
	dy = y1 - y0;
	x = x0 << 10;
	y = y0 << 10;
	if (dx < 0) {
		dx = - dx;
	}
	if (dy < 0) {
		dy = - dy;
	}
	if (dx >= dy) {
		len = dx + 1;
		if (x0 > x1) {
			dx = -1024;
		} else {
			dx =  1024;
		}
		if (y0 <= y1) {
			dy = ((y1 - y0 + 1) << 10) / len;
		} else {
			dy = ((y1 - y0 - 1) << 10) / len;
		}
	} else {
		len = dy + 1;
		if (y0 > y1) {
			dy = -1024;
		} else {
			dy =  1024;
		}
		if (x0 <= x1) {
			dx = ((x1 - x0 + 1) << 10) / len;
		} else {
			dx = ((x1 - x0 - 1) << 10) / len;
		}
	}

	for (i = 0; i < len; i++) {
		sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col;
		x += dx;
		y += dy;
	}

	return;
}

