;
; コンソールログ記録ユーティリティ Version 2.00a
;
; Copyright (c) 1995 Delmonta
;
;******************************************************************************
;                                    定義部
;******************************************************************************
DEFAULTBUFFERSIZE	equ	8192	; デフォルトのバッファサイズ
MIN_FLUSH		equ	4096	; フラッシュを行う最小の幅
MAXBUFSIZE		equ	32768	; バッファサイズとして許容する最大の値
;----------------------------int 2FHのコマンドID-------------------------------
; AX=0F334H,DH=0,DL=コマンドIDとしてint 2FHを発行する。
;           (1)必ずint 21Hが使用可能な状態でなければならない。
;           (2)特に記述のないレジスタは保存される。
;------------------------------------------------------------------------------
CMD_CHKISRESIDENT	equ	0
	; <in>  nothing
	; <out> インストールされている   : AL=0
	;       インストールされていない : AL=34H (DOSの仕様)

CMD_RELEASE	equ	1
	; <in>  nothing
	; <out> AX= 0  成功 ; ES   常駐部のPSP(自分でメモリの解放はしない)
	;       AX=-1  失敗(割り込みベクタが変更されている)

CMD_GETSET_ISACTIVE	equ	2
	; <in>  BL= 0    中断する
	;       BL= 1    再開する
	;       BL=-1    現在の状態を得る
	;
	; <out> BL=0,1で呼び出した場合  nothing
	;       BL=-1 で呼び出した場合  BL=現在の状態
;------------------------------------------------------------------------------
.8086

INT_ID		equ	0F000H+'D'+'e'+'l'+'m'+'o'+'n'+'t'+'a'	;0F334H
ID_CONSLOG2	equ	0
;------------------------------------マクロ------------------------------------
DOS_CLOSE	macro	handle
	mov	AH,3EH
	mov	BX,handle
	int	21H
endm

PUSHM	macro	regs
	irp	arg,<regs>
		push	arg
	endm
endm

POPM	macro	regs
	irp	arg,<regs>
		pop	arg
	endm
endm

;------------------------------------------------------------------------------
DGROUP	group	RESIDENT,CODE,DATA,BSS
;******************************************************************************
;                                    常駐部
;******************************************************************************
RESIDENT segment byte public 'CODE'
	assume	CS:RESIDENT,DS:nothing,ES:nothing
	org	0
;---------------------------常駐部で使用する変数-------------------------------
old2FH	dd	?
old21H	dd	?
old29H	dd	?

psp	dw	?

buffersize	dw	DEFAULTBUFFERSIZE
char_in_buffer	dw	0
filehandle	dw	?
indosflag	dd	?	; InDOSフラグと致命的エラーフラグ

isactive	db	1
isinside	db	0
;--------------------------------int 2FHハンドラ-------------------------------
int2FH	proc	far

	CHKVECT	macro	id,of
		mov	AX,3500H+id
		int	21H
		cmp	BX,offset DGROUP:of
		jnz	_2F_2_error
		mov	AX,ES
		cmp	AX,DX
		jnz	_2F_2_error
	endm

	cmp	AX,INT_ID
	jz	_2F_01
	jmp	_2F_next
_2F_01:
	cmp	DH,ID_CONSLOG2
	jz	_2F_02
	jmp	_2F_next
_2F_02:
	clc
	call	flush

	cmp	DL,CMD_CHKISRESIDENT
	jnz	_2F_1
	mov	AL,0
	iret
_2F_1:
	cmp	DL,CMD_GETSET_ISACTIVE
	jnz	_2F_2
	cmp	BL,-1
	jnz	_2F_1_set
	mov	BL,CS:[isactive]
	iret
_2F_1_set:
	mov	CS:[isactive],BL
	iret

_2F_2:
	cmp	DL,CMD_RELEASE
	jnz	_2F_3

	PUSHM	<BX,DX,ES>

	mov	DX,CS

	CHKVECT	21H,int21H
	CHKVECT	29H,int29H
	CHKVECT	2FH,int2FH

	stc
	call	flush

	push	DS

	mov	AX,2521H
	lds	DX,CS:[old21H]
	int	21H

	mov	AX,2529H
	lds	DX,CS:[old29H]
	int	21H

	mov	AX,252FH
	lds	DX,CS:[old2FH]
	int	21H

	pop	DS

	mov	ES,CS:[psp]
	POPM	<AX,DX,BX>
	mov	AX,0
	iret

_2F_2_error:
	POPM	<ES,DX,BX>
	mov	AX,-1
	iret

_2F_3:
_2F_next:
	jmp	CS:[old2FH]

int2FH	endp
;------------------------------int 21Hハンドラ---------------------------------
int21H	proc	far
	PUSHM	<DS,BX>

	cmp	CS:[char_in_buffer],MIN_FLUSH
	jc	_21_1
	cmp	CS:[isinside],0
	jnz	_21_1

	lds	BX,CS:[indosflag]
	cmp	word ptr [BX],0	; InDOSフラグ ＋ 致命的エラーフラグ
	jnz	_21_1

	clc
	call	flush
_21_1:
	POPM	<BX,DS>
	jmp	CS:[old21H]

int21H	endp
;--------------------------------int 29Hハンドラ-------------------------------
int29H	proc	far
	push	BX
	cmp	CS:[isactive],0
	jz	_29_1
	mov	BX,CS:[char_in_buffer]
	cmp	BX,CS:[buffersize]
	jnc	_29_1
	mov	CS:[buffer+BX],AL
	inc	BX
	mov	CS:[char_in_buffer],BX
_29_1:
	pop	BX
	jmp	CS:[old29H]
int29H	endp
;---------------------------バッファのフラッシュ-------------------------------
;<in>  CF ファイルをクローズするなら1


flush	proc	near
	mov	CS:[isinside],1

	PUSHM	<AX,BX,CX,DX,DS>
	pushf

	mov	AH,51H
	int	21H
	push	BX
	mov	AH,50H
	mov	BX,CS:[psp]
	int	21H

	push	CS
	pop	DS
	mov	AH,40H
	mov	BX,[filehandle]
	mov	CX,[char_in_buffer]
	mov	DX,offset DGROUP:buffer
	int	21H

	pop	BX
	popf
	push	BX
	jnc	noclose

	mov	AH,3eH
	mov	BX,[filehandle]
	int	21H

noclose:
	pop	BX
	mov	AH,50H
	int	21H

	mov	[char_in_buffer],0
	mov	[isinside],0

	POPM	<DS,DX,CX,BX,AX>
	ret
flush	endp
;------------------------------------------------------------------------------
buffer	label	byte
RESIDENT ends
;******************************************************************************
;                            スタートアップルーチン
;******************************************************************************
CODE	segment byte public 'CODE'
	assume	CS:DGROUP,DS:DGROUP
;--------------------------------スタートアップ--------------------------------
start	proc	near
	push	CS			;セグメントレジスタの初期化
	pop	DS
	mov	[psp],ES

	mov	AX,3000h
	int	21H
	cmp	AL,3
	jnc	_chkver_ok
	jmp	chkver_fail
_chkver_ok:
	mov	AX,INT_ID		;常駐チェック
	mov	DX,ID_CONSLOG2*256+CMD_CHKISRESIDENT
	int	2FH

	sub	AL,(INT_ID mod 256)
	mov	[isinstalled],AL

	mov	DX,offset DGROUP:titlemessage	;タイトルの表示
	mov	AH,9
	int	21H

	mov	SI,81H			;コマンドライン読み込み開始
	mov	BX,SI
	add	BL,ES:[80H]
	mov	byte ptr ES:[BX],0
repeat:
	call	skipsp
	cmp	AL,0		;コマンドラインが尽きた→ヘルプ
	jnz	_01
	jmp	showhelpmessage
_01:
	cmp	AL,'-'		;ファイル名→インストール
	jnz	install

	inc	SI
	mov	AL,ES:[SI]
	inc	SI
	and	AL,0DFH		;toupper

	mov	DI,offset DGROUP:next	;jmp先からretで戻ってくるアドレス
	push	DI

	cmp	AL,'S'
	jnz	_02
	jmp	stop
_02:
	cmp	AL,'R'
	jnz	_03
	jmp	release
_03:
	cmp	AL,'B'
	jnz	_04
	jmp	chgbufsize	; if z
_04:
	jmp	showhelpmessage	; if nz
next:
	call	findsp
	jmp	repeat

titlemessage	db	"コンソールログ記録ユーティリティ Version 2.00a",13,10
		db	"Copyright (c) 1995 Delmonta",13,10,'$'
start	endp
;******************************************************************************
;                                 インストール
;******************************************************************************
install	proc	near
; <in> ES:SI ファイル名
;
	cmp	[isinstalled],0
	jnz	already_installed

	push	ES
	pop	DS

	push	SI
	call	findsp
	mov	byte ptr [SI],0

	pop	DX		; ファイルをオープン
	mov	AH,3CH
	mov	CX,0
	int	21H
	jc	openerror

	push	CS
	pop	DS
	mov	[filehandle],AX

	call	hookvector
	call	puttime

	DOS_CLOSE	0	;stdin
	DOS_CLOSE	1	;stdout
	DOS_CLOSE	2	;stderr
	DOS_CLOSE	3	;stdaux
	DOS_CLOSE	4	;stdprn

	mov	DX,[buffersize]
	add	DX,(offset DGROUP:buffer)+15
	mov	CL,4
	shr	DX,CL

	mov	AX,CS
	sub	AX,[psp]
	add	DX,AX

	mov	AX,3100H
	int	21H
install	endp
;------------------------すでに常駐している場合の処理--------------------------
already_installed	proc	near
	mov	DX,offset DGROUP:already_message
	mov	AL,1
	jmp	puts_exit

already_message	db	"すでに常駐しています.",13,10,'$'

already_installed	endp
;--------------------------ファイルオープンのエラー----------------------------
openerror	proc	near
; <in> DS(==ES):DX ファイル名

	mov	SI,DX
operr_loop:
	mov	DL,[SI]
	inc	SI
	cmp	DL,0
	jz	operr_endloop
	mov	AH,2
	int	21H
	jmp	operr_loop
operr_endloop:
	push	CS
	pop	DS
	mov	DX,offset DGROUP:operr_message
	mov	AL,1
	jmp	puts_exit

operr_message	db	" がオーブンできません.",13,10,'$'

openerror	endp
;---------------------------割り込みベクタのフック-----------------------------
hookvector	proc	near
; <in> <out> nothing
; <break> ES,AX,BX,DX
;
	mov	AH,34H
	int	21H
	dec	BX		; 致命的エラーフラグを同時に判定するため
	mov	word ptr [indosflag],BX
	mov	word ptr 2[indosflag],ES

	mov	AX,3521H
	int	21H
	mov	word ptr [old21H],BX
	mov	word ptr 2[old21H],ES

	mov	AX,3529H
	int	21H
	mov	word ptr [old29H],BX
	mov	word ptr 2[old29H],ES

	mov	AX,352FH
	int	21H
	mov	word ptr [old2FH],BX
	mov	word ptr 2[old2FH],ES

	mov	DX,offset DGROUP:int21H	;DS==CS
	mov	AX,2521H
	int	21H

	mov	DX,offset DGROUP:int29H
	mov	AX,2529H
	int	21H

	mov	DX,offset DGROUP:int2FH
	mov	AX,252FH
	int	21H

	ret
hookvector	endp
;-------------------------------現在時刻の表示---------------------------------
puttime	proc	near
; <break> AX,CX,DX
;
	mov	AH,2CH
	int	21H

	mov	AL,CH
	aam
	add	[hour_l],AL
	add	[hour_h],AH

	mov	AL,CL
	aam
	add	[min_l],AL
	add	[min_h],AH

	mov	AL,DH
	aam
	add	[sec_l],AL
	add	[sec_h],AH

	mov	AH,9
	mov	DX,offset DGROUP:time_t
	int	21H
	ret

time_t	db	"記録開始時刻 "
	hour_h	db	'0'
	hour_l	db	'0'
		db	':'
	min_h	db	'0'
	min_l	db	'0'
		db	':'
	sec_h	db	'0'
	sec_l	db	'0'
		db	13,10,'$'

puttime	endp
;******************************************************************************
;                              各コマンドの処理
;******************************************************************************
;----------------------------------一時停止------------------------------------
stop	proc	near
	cmp	[isinstalled],0
	jnz	stop_1
	jmp	not_installed
stop_1:
	mov	AX,INT_ID
	mov	DX,ID_CONSLOG2*256+CMD_GETSET_ISACTIVE
	mov	BL,-1
	int	2FH
	cmp	BL,0
	jz	activate

;inactivate:
	mov	BL,0
	int	2FH
	mov	DX,offset DGROUP:mes_activated
	mov	AL,0
	jmp	puts_exit

activate:
	mov	BL,1
	int	2FH
	mov	DX,offset DGROUP:mes_inactivated
	mov	AL,0
	jmp	puts_exit

mes_inactivated	db	"記録を中断しました.",13,10,'$'
mes_activated	db	"記録を再開しました.",13,10,'$'

stop	endp
;----------------------------------常駐解除------------------------------------
release	proc	near
	cmp	[isinstalled],0
	jnz	rel_1
	jmp	not_installed
rel_1:
	mov	AX,INT_ID
	mov	DX,ID_CONSLOG2*256+CMD_RELEASE
	int	2FH
	cmp	AX,0
	jnz	release_err
	mov	AH,49H
	int	21H
	mov	DX,offset DGROUP:mes_released
	mov	AL,0
	jmp	puts_exit
release_err:
	mov	DX,offset DGROUP:mes_noreleased
	mov	AL,1
	jmp	puts_exit

mes_released	db	"メモリを解放しました.",13,10,'$'
mes_noreleased	db	"解放できません.",13,10,'$'

release	endp
;-----------------------------バッファサイズの設定-----------------------------
chgbufsize	proc	near
; <in>     ES:SI 10進数へのポインタ
; <out>    ES:SI 10進数の直後へのポインタ
; <break>  AX,BX,CX,DX
	mov	AX,0
	mov	BX,10
	mov	CX,0
chgbuf_rep:
	mov	CL,ES:[SI]
	sub	CL,'0'
	jc	chgbuf_end
	cmp	CL,10
	jnc	chgbuf_end
	inc	SI
	mul	BX
	cmp	DX,0
	jnz	chgbuf_overflow
	add	AX,CX
	jmp	chgbuf_rep
chgbuf_end:
	mov	[buffersize],AX
	cmp	AX,MAXBUFSIZE
	jnc	chgbuf_overflow
	ret

chgbuf_overflow:
	mov	DX,offset DGROUP:overflow_message
	mov	AL,1
	jmp	puts_exit

overflow_message:
	DECIMAL	macro arg
		db	'&arg'
	endm

	db	"バッファサイズは"
	DECIMAL	%MIN_FLUSH
	db	"バイト～"
	DECIMAL	%MAXBUFSIZE
	db	"バイトにしてください.",13,10,'$'

chgbufsize	endp
;----------------------------ヘルプメッセージの出力----------------------------
showhelpmessage	proc	near
	mov	DX,offset DGROUP:helpmessage
	mov	AL,0
	jmp	puts_exit

helpmessage	db	13,10
		db	"[非常駐時]",13,10
		db	13,10
		db	"    conslog2 [-Bバッファサイズ] ログファイル名",13,10
		db	13,10
		db	"[常駐時]",13,10
		db	13,10
		db	"    一時停止/再開 : conslog -s",13,10
		db	"    常駐解除      : conslog -r",13,10
		db	13,10,'$'
showhelpmessage	endp
;******************************************************************************
;                              下請けルーチン
;******************************************************************************
;---------------------------スペースの処理-------------------------------------
skipsp	proc	near
;空白を飛ばす
;    <in>  ES:SI   ASCIIZ文字列
;    <out> ES:SI   飛ばした空白の後へのポインタ
;          AL      ES:[SI]と同じもの
sksp_1:
	mov	AL,ES:[SI]
	cmp	AL,9		;TAB
	jz	sksp_2
	cmp	AL,' '
	jz	sksp_2
	ret
sksp_2:
	inc	SI
	jmp	sksp_1
skipsp	endp

findsp	proc	near
; 空白を探す(見つからなければ'\0'へのポインタを返す)
;    <in>  ES:SI   ASCIIZ文字列
;    <out> ES:SI   空白または'\0'へのポインタ
;          AL      ES:[SI]と同じ

fisp_1:
	mov	AL,ES:[SI]
	cmp	AL,9		;TAB
	jz	fisp_2
	cmp	AL,' '
	jz	fisp_2
	cmp	AL,0		;'\0'
	jz	fisp_2

	inc	SI
	jmp	fisp_1
fisp_2:
	ret
findsp	endp
;-----------------------------文字列を表示して終了-----------------------------
puts_exit	proc	near
;<in> DS:DX  表示する文字列
;     AL     終了コード

	push	AX
	mov	AH,9
	int	21H
	pop	AX
	mov	AH,4CH
	int	21H
puts_exit	endp
;--------------まだ常駐していない旨のメッセージを出して終了--------------------
not_installed	proc	near
	mov	DX,offset DGROUP:mes_notinstalled
	jmp	puts_exit

mes_notinstalled	db	"まだ常駐していません.",13,10,'$'

not_installed	endp
;-----------------------DOS 1.x,2.xで起動した場合の処理------------------------
chkver_fail	proc	near
	mov	DX,offset DGROUP:mes_chkver_fail
	mov	AH,9
	int	21H
	mov	AH,0
	int	21H

mes_chkver_fail	db	"CONSLOG2はMS-DOS Ver3以上専用です。",13,10,'$'

chkver_fail	endp
;------------------------------------------------------------------------------
CODE	ends
;******************************************************************************
;                                   データ
;******************************************************************************
DATA	segment byte public 'DATA'
DATA	ends

BSS	segment byte public 'BSS'
	isinstalled	db	?
BSS	ends

STACK	segment word public 'STACK'
	db	8192 dup (?)
STACK	ends
;------------------------------------------------------------------------------
end	start
