#include	<dos.h>
#include	<stdlib.h>

#pragma check_stack (off)

struct TOKEI {
	unsigned short	nen;
	unsigned char	data[8];
} jikan;

union REGS	inregs,outregs;
struct SREGS	segregs;

int		X,Y;
int		Col;

#define		ColDef	5
#define		XDef	79
#define		YDef	0

/******************************************************************************
	VRAM データ設定

	入力	: 
			x    - 設定桁位置
			y    - 設定行位置
			data - 表示データ
			attr - 表示属性
	出力	: なし
	戻り値	: なし
******************************************************************************/
void vram_set(x,y,data,atr)
int	x,y,data,atr;
{
	int	vram;

	vram=x*2 + y*160;
	if (vram>3998) vram=3998;
	*(int far *)(0xc8000000+vram) = data | (atr<<8);
}

/******************************************************************************
	時間表示

	入力	: buffer - 表示バッファ
	出力	: なし
	戻り値	: なし
******************************************************************************/
void disp_time(buffer)
char	*buffer;
{
	int	i,x,y,n,atr=0x20;
	void	vram_set();

	n=0;
	while (buffer[n++])
		;
	n--;
	x=X;
	if (x+n>80)
		x=80-n;
	y=Y;
	if (y>24)
		y=24;
	atr |= Col;
	for (i=0;i<n;++i)
		vram_set(x++,y,buffer[i],atr);
}

/******************************************************************************
		整数 -> 文字列
******************************************************************************/
char *itoc( ivalue,s,radix )
int	ivalue;
char	*s;
int	radix;
{
	char	*s1;
	int	sign;

	char	*strrev();

	s1=s;
	if ((radix==10) && (ivalue<0)) {	/* バッファアドレスセーブ */
		sign=1;
		ivalue=-ivalue;
	}
	else {
		sign=0;
	}
	do {
		*s=ivalue%radix;
		*s+=(*s<=9 ? '0' :('A'-10));
		++s;
	} while (ivalue/=radix);
	if (sign)				/* 符号あり？ */
		*s++='-';
	*s='\0';
	strrev(s1);				/* 文字列を逆に並べる */
	return s1;
}

/******************************************************************************
	時間の変更

	入力	: 
			buffer - 変更した時間設定バッファ
			data   - 時間データ
			radix  - 基数
	出力	: 
			buffer - 変更した時間
	戻り値	: なし
******************************************************************************/
void set_time(buffer,data,radix)
char	*buffer;
int	data;
int	radix;
{
	if (data<10) {
		*buffer++ = '0';
	}
	itoc(data,buffer,radix);
}

/******************************************************************************
	時間を表示形式に変更

	入力	: 
			buffer - 変更した時間設定バッファ
	出力	: 
			buffer - 変更した時間
	戻り値	: なし
******************************************************************************/
void conv_time(buffer)
char	*buffer;
{
	void	set_time();

	set_time(buffer,jikan.nen-1900,10);			/* 年を設定 */
	buffer[2]='/';
	set_time(buffer+3,jikan.data[0],10);		/* 月を設定 */
	buffer[5]='/';
	set_time(buffer+6,jikan.data[1],10);		/* 日を設定 */
	buffer[8]=' ';
	set_time(buffer+9,jikan.data[3],10);		/* 時を設定 */
	buffer[11]=':';
	set_time(buffer+12,jikan.data[4],10);		/* 分を設定 */
	buffer[14]=':';
	set_time(buffer+15,jikan.data[5],10);		/* 秒を設定 */
	buffer[17]='\0';
}

/******************************************************************************
	時間の取り出し

	入力	: なし
	出力	: data - 取り出した時間
	戻り値	: なし
******************************************************************************/
void get_time()
{
	int	int86x(),i;

	segread(&segregs);
	segregs.es=segregs.ss;
	inregs.h.ah=1;
	inregs.x.di=(int)&jikan;
	int86x(0x96,&inregs,&outregs,&segregs);
}

/******************************************************************************
	時計表示

	入力	: なし
	出力	: なし
	戻り値	: なし
******************************************************************************/
void tokei()
{
	void	get_time();
	void	conv_time(),disp_time();
	char	*dispdata="00/00/00 00:00:00";

	get_time();
	conv_time(dispdata);
	disp_time(dispdata);
}

/******************************************************************************
	本来のINT28のベクタを格納
******************************************************************************/
void (interrupt far *int28org)();

/******************************************************************************
	INT28の横取り
******************************************************************************/
void interrupt far int28hook()
{
	tokei();
	_chain_intr(int28org);
}

/******************************************************************************
	TITLE
******************************************************************************/
char *title="ぱお TOKEI ";

/******************************************************************************
	常駐部にアクセスするマクロ
******************************************************************************/
long adrsdiff;
#define Access(t,p)(*(t far *)((long)(char far *)&p - adrsdiff))

/******************************************************************************
	常駐/非常駐のトグルスイッチ
******************************************************************************/
int main( int ac,char *av[] )
{
	int	keepsiz;
	extern	end;

	if (ac>1) {
		Col=*av[1]-'0';
		if (ac>2) {
			X=(*av[2]-'0');
			if (*(av[2]+1))
				X=X*10 + *(av[2]+1)-'0';
			if (ac>3) {
				Y=(*av[3]-'0');
				if (*(av[3]+1))
					Y=Y*10 + *(av[3]+1)-'0';
			}
			else
				Y=YDef;
		}
		else {
			X=XDef;
			Y=YDef;
		}
	}
	else {
		Col=ColDef;
		X=XDef;
		Y=YDef;
	}
	cputs(title);
	int28org = _dos_getvect(0x28);
	adrsdiff = (long)int28hook - (long)int28org;
	if (check_stay()) {
		_dos_setvect(0x28,(void(interrupt far *)())Access(void far *,int28org));		_dos_freemem(Access(unsigned,_psp));
		cputs("解除しちゃった");
	}
	else {
		_dos_freemem(*(unsigned far *)(((long)_psp <<16)|0x002c));
		keepsiz = ((char huge *)&end - (char huge *)((long)_psp << 16)+15)/16;
		/*	+ 128	*/
		_dos_setvect(0x28,int28hook);
		cputs("常駐しま〜す");
		_dos_keep(0,keepsiz);
	}
	return(0);
}

/******************************************************************************
	常駐/非常駐のチェック
******************************************************************************/
int check_stay()
{
	register char *s,far *t;
	
	if (adrsdiff & 0xffff != 0) return(0);
	
	s=title;
	t=(char far *)((long)(char far *)title - adrsdiff);

	while (*s) {
		if(*(s++)!=*(t++)) return(0);
	}
	return(1);
}
