misc/set232c.s
;========================================================================================
;  set232c.s
;  Copyright (C) 2003-2024 Makoto Kamada
;
;  This file is part of the XEiJ (X68000 Emulator in Java).
;  You can use, modify and redistribute the XEiJ if the conditions are met.
;  Read the XEiJ License for more details.
;  https://stdkmd.net/xeij/
;========================================================================================

;----------------------------------------------------------------
;
;	set232c.x
;		RS-232Cの設定を変更します。
;
;	最終更新
;		2024-05-04
;
;	作り方
;		has060 -i include -o set232c.o -w set232c.s
;		lk -o set232c.x set232c.o
;
;	使い方
;		set232c オプション …
;
;	オプション
;		-5
;			5MHzの場合のボーレートを表示します。(デフォルト)
;		-7
;			7.3728MHzの場合のボーレートを表示します。
;		-c
;			SPEED.Xと同様に、現在の設定を変更します。(デフォルト)
;		-i
;			初期値$4E07 9600 b8 pn s1 xonを使います。
;		-q
;			設定を表示しません。
;		-s
;			SWITCH.Xと同様に、起動時の設定を変更します。
;		$xxxx
;			設定値を4桁の16進数で指定します。
;		75
;		150
;		300
;		600
;		1200
;		2400
;		4800
;		9600
;		19200
;		38400
;		76800
;			5MHzの場合のボーレートを指定します。
;		112.5
;		225
;		450
;		900
;		1800
;		3600
;		7200
;		14400
;		28800
;		57600
;		115200
;			7.3728MHzの場合のボーレートを指定します。
;		b5
;		b6
;		b7
;		b7s
;		b8
;			データ長を指定します。b7sはSI/SOを有効にします。
;		pn
;		po
;		pe
;			パリティを指定します。
;		s1
;		s1.5
;		s2
;			ストップビットを指定します。
;		none
;		xon
;		rts
;			フロー制御を指定します。
;
;	更新履歴
;		2024-02-07
;			作成。
;		2024-02-08
;			7.5MHzの場合のボーレートの指定と表示を追加。
;		2024-05-04
;			7.5MHzの表記を7.3728MHzに変更。
;
;----------------------------------------------------------------

	.include	control2.mac
	.include	doscall.mac
	.include	iocscall.mac
	.include	push2.mac
	.include	sram.equ
	.include	sysport.equ

TITLE_STRING	reg	'set232c.x (2024-05-04)'

	.text

;大域レジスタを初期化する
aBUF	reg	a6
	lea.l	buffer(pc),aBUF		;文字列バッファ
r	reg	-buffer(aBUF)		;文字列バッファ以外も(~)rで相対アクセスできる
;<a6.l:文字列バッファ。相対アクセスのベースアドレス

;引数を読み取る
	sf.b	(seven_flag)r
	sf.b	(initial_flag)r
	sf.b	(quiet_flag)r
	sf.b	(startup_flag)r
	moveq.l	#0,d6			;変更する項目のマスク
	moveq.l	#0,d7			;変更後の設定値
	addq.l	#1,a2			;コマンドライン
	dostart
		move.b	(aBUF),d0		;引数の1文字目
		if	<cmp.b #'-',d0>,eq	;1文字目が'-'
			move.b	1(aBUF),d0		;2文字目
			bsr	tolower
			if	<cmp.b #'5',d0>,eq		;-5
				sf.b	(seven_flag)r
			elif	<cmp.b #'7',d0>,eq		;-7
				st.b	(seven_flag)r
			elif	<cmp.b #'c',d0>,eq		;-c
				sf.b	(startup_flag)r
			elif	<cmp.b #'i',d0>,eq		;-i
				st.b	(initial_flag)r
			elif	<cmp.b #'q',d0>,eq		;-q
				st.b	(quiet_flag)r
			elif	<cmp.b #'s',d0>,eq		;-s
				st.b	(startup_flag)r
			else
				goto	error_exit
			endif
		elif	<cmp.b #'$',d0>,eq	;1文字目が'$'
			lea.l	1(aBUF),a0		;2文字目
			bsr	stoh			;16進数を読み取る
			goto	cs,error_exit		;16進数の文字がない
			goto	<cmp.l #$0000FFFF,d0>,hi,error_exit	;範囲外
			goto	<tst.w d0>,eq,error_exit	;未初期化
			goto	<cmp.w #$FFFF,d0>,eq,error_exit	;問い合わせ
			moveq.l	#-1,d6			;すべてのビットを変更する
			move.w	d0,d7			;16進数の値
		else				;キーワードを探す
			do
				lea.l	(keywords)r,a3
				dostart
					move.l	(a3)+,d2		;周波数|マスク
					move.w	(a3)+,d3		;設定値
					movea.l	aBUF,a0
					movea.l	a3,a1			;キーワードと
					bsr	stricmp			;比較する
					if	eq			;一致したら
						or.w	d2,d6			;項目のマスクを追加する
						not.w	d2
						and.w	d2,d7			;変更する項目を消して
						or.w	d3,d7			;書き換える
						break2	t			;この引数は終わり
					endif
					adda.w	d1,a3			;次のキーワードへ
				start
					move.w	(a3)+,d1		;キーワードの長さ
				while	ne
				goto	error_exit		;キーワードが見つからなかった
			while	f			;一致したときの出口
		endif
	start
		movea.l	aBUF,a0		;文字列バッファへ
		movea.l	a2,a1		;コマンドラインの
		bsr	argcpy		;引数をコピーする
		movea.l	a1,a2
	while	ne
;<d6.w:変更する項目のマスク
;<d7.w:変更後の設定値

;設定を読み出す
	if	<tst.b (initial_flag)r>,ne	;初期値を使う
;			  FE DC BA 9 8 7 6543210
		move.w	#%01_00_11_1_0_0_0000111,d0	;$4E07 9600 b8 pn s1 xon
;			  || || || | | | 9600bps
;			  || || || | | RTSなし(RSDRV.SYS)
;			  || || || | SISOなし
;			  || || || XONあり
;			  || || 8ビット
;			  || パリティなし
;			  ストップ1
	elif	<tst.b (startup_flag)r>,ne	;起動時の設定を読み出す
		lea.l	SRAM_AUX_MODE,a1
		IOCS	_B_WPEEK
	else				;現在の設定を読み出す
		moveq.l	#-1,d1
		IOCS	_SET232C
	endif
	move.w	d0,d4			;変更前の設定値
;<d4.w:変更前の設定値

;設定を変更する
	move.w	d4,d5			;変更後の設定値
	not.w	d6
	and.w	d6,d5			;変更する項目を消して
	or.w	d7,d5			;書き換える
;<d5.w:変更後の設定値

;設定を書き込む
	if	<tst.b (startup_flag)r>,ne	;起動時の設定を書き込む
		moveq.l	#$31,d1
		lea.l	SYSPORT_SRAM,a1
		IOCS	_B_BPOKE
		move.w	d5,d1
		lea.l	SRAM_AUX_MODE,a1
		IOCS	_B_WPOKE
		moveq.l	#$00,d1
		lea.l	SYSPORT_SRAM,a1
		IOCS	_B_BPOKE
	else				;現在の設定を書き込む。初期化を伴うので変化しなくても書き込む
		move.w	d5,d1
		IOCS	_SET232C
	endif

;設定を表示する
	if	<tst.b (quiet_flag)r>,eq
		movea.l	aBUF,a0
		lea.l	(current_message)r,a1
		if	<tst.b (startup_flag)r>,ne
			lea.l	(startup_message)r,a1
		endif
		bsr	strcpy
		lea.l	(five_message)r,a1
		if	<tst.b (seven_flag)r>,ne
			lea.l	(seven_message)r,a1
		endif
		bsr	strcpy
		move.w	d5,d0			;設定値
		bsr	h4tos
		move.b	#' ',(a0)+
		lea.l	(keywords)r,a3
		dostart
			move.l	(a3)+,d2		;周波数|マスク
			move.w	(a3)+,d3		;設定値
			moveq.l	#17,d0			;5MHzの場合は周波数が%10のキーワードを表示しない
			if	<tst.b (seven_flag)r>,ne
				moveq.l	#16,d0			;7.3728MHzの場合は周波数が%01のキーワードを表示しない
			endif
			if	<btst.l d0,d2>,eq	;表示するとき
				move.w	d5,d0
				and.w	d2,d0			;項目を取り出して
				if	<cmp.w d3,d0>,eq	;比較して一致したら
					movea.l	a3,a1			;キーワードを
					bsr	strcpy			;コピーする
					move.b	#' ',(a0)+
				endif
			endif
			adda.w	d1,a3				;次のキーワードへ
		start
			move.w	(a3)+,d1		;キーワードの長さ
		while	ne
		if	<cmpi.b #' ',-1(a0)>,eq	;最後が' 'ならば
			subq.l	#1,a0			;1文字戻る
		endif
		bsr	crlf
		movea.l	aBUF,a0
		bsr	print			;表示する
	endif

;終了
	DOS	_EXIT

error_exit:
	lea.l	(how_to_use)r,a0
	bsr	more
	move.w	#1,-(sp)
	DOS	_EXIT2

how_to_use:
	.dc.b	TITLE_STRING,13,10
	.dc.b	'Change current or startup RS-232C settings',13,10
	.dc.b	'    -5      Display baud rate at 5 MHz (default)',13,10
	.dc.b	'    -7      Display baud rate at 7.3728 MHz',13,10
	.dc.b	'    -c      Change current RS-232C settings as in SPEED.X (default)',13,10
	.dc.b	'    -i      Use initial setting value $4E07 9600 b8 pn s1 xon',13,10
	.dc.b	'    -q      Do not display settings',13,10
	.dc.b	'    -s      Change startup RS-232C settings as in SWITCH.X',13,10
	.dc.b	'    $xxxx   Specify setting value by 4-digit hexadecimal number',13,10
	.dc.b	'  Baud rate at 5 MHz',13,10
	.dc.b	'    75',13,10
	.dc.b	'    150',13,10
	.dc.b	'    300',13,10
	.dc.b	'    600',13,10
	.dc.b	'    1200',13,10
	.dc.b	'    2400',13,10
	.dc.b	'    4800',13,10
	.dc.b	'    9600',13,10
	.dc.b	'    19200',13,10
	.dc.b	'    38400',13,10
	.dc.b	'    76800',13,10
	.dc.b	'  Baud rate at 7.3728 MHz',13,10
	.dc.b	'    112.5',13,10
	.dc.b	'    225',13,10
	.dc.b	'    450',13,10
	.dc.b	'    900',13,10
	.dc.b	'    1800',13,10
	.dc.b	'    3600',13,10
	.dc.b	'    7200',13,10
	.dc.b	'    14400',13,10
	.dc.b	'    28800',13,10
	.dc.b	'    57600',13,10
	.dc.b	'    115200',13,10
	.dc.b	'  Data',13,10
	.dc.b	'    b5      5-bit',13,10
	.dc.b	'    b6      6-bit',13,10
	.dc.b	'    b7      7-bit',13,10
	.dc.b	'    b7s     7-bit with SI/SO',13,10
	.dc.b	'    b8      8-bit',13,10
	.dc.b	'  Parity',13,10
	.dc.b	'    pn      Non-parity',13,10
	.dc.b	'    po      Odd parity',13,10
	.dc.b	'    pe      Even parity',13,10
	.dc.b	'  Stop bit',13,10
	.dc.b	'    s1      Stop 1-bit',13,10
	.dc.b	'    s1.5    Stop 1.5-bit',13,10
	.dc.b	'    s2      Stop 2-bit',13,10
	.dc.b	'  Flow control',13,10
	.dc.b	'    none    No flow control',13,10
	.dc.b	'    xon     XON/XOFF flow control',13,10
	.dc.b	'    rts     RTS/CTS flow control',13,10
	.dc.b	0
current_message:
	.dc.b	'Current RS-232C settings at ',0
startup_message:
	.dc.b	'Startup RS-232C settings at ',0
five_message:
	.dc.b	'5 MHz are: $',0
seven_message:
	.dc.b	'7.3728 MHz are: $',0
	.even

;キーワードのリスト
keyword	.macro	freq,mask,value,string
	.dc.w	@tail-@head
	.dc.w	freq			;周波数
	.dc.w	mask			;マスク
	.dc.w	value			;設定値
@head:	.dc.b	string,0		;キーワード
	.even
@tail:
	.endm
keywords:
	keyword	%01,$001F,$0000,'75'	;ボーレート(5MHz)
	keyword	%01,$001F,$0001,'150'
	keyword	%01,$001F,$0002,'300'
	keyword	%01,$001F,$0003,'600'
	keyword	%01,$001F,$0004,'1200'
	keyword	%01,$001F,$0005,'2400'
	keyword	%01,$001F,$0006,'4800'
	keyword	%01,$001F,$0007,'9600'
	keyword	%01,$001F,$0008,'19200'
	keyword	%01,$001F,$0009,'38400'
	keyword	%01,$001F,$000A,'76800'
	keyword	%10,$001F,$0000,'112.5'	;ボーレート(7.3728MHz)
	keyword	%10,$001F,$0001,'225'
	keyword	%10,$001F,$0002,'450'
	keyword	%10,$001F,$0003,'900'
	keyword	%10,$001F,$0004,'1800'
	keyword	%10,$001F,$0005,'3600'
	keyword	%10,$001F,$0006,'7200'
	keyword	%10,$001F,$0007,'14400'
	keyword	%10,$001F,$0008,'28800'
	keyword	%10,$001F,$0009,'57600'
	keyword	%10,$001F,$000A,'115200'
	keyword	%00,$0D00,$0000,'b5'	;データ
	keyword	%00,$0D00,$0400,'b6'
	keyword	%00,$0D00,$0800,'b7'
	keyword	%00,$0D00,$0900,'b7s'	;SISO
	keyword	%00,$0D00,$0C00,'b8'
	keyword	%00,$3000,$0000,'pn'	;パリティ。IPLROMの$00ED001AとSPEED.Xの$0926のpnは00
	keyword	%00,$3000,$1000,'po'
	keyword	%00,$3000,$2000,'pn'	;SWITCH.Xの$00ED001Aのpnは10
	keyword	%00,$3000,$3000,'pe'
	keyword	%00,$C000,$4000,'s1'	;ストップビット
	keyword	%00,$C000,$8000,'s1.5'
	keyword	%00,$C000,$C000,'s2'
	keyword	%00,$0280,$0000,'none'	;フロー制御
	keyword	%00,$0280,$0200,'xon'
	keyword	%00,$0280,$0080,'rts'
	.dc.w	0			;番兵

	.bss
seven_flag:
	.dc.b	1			;-7 7.3728MHzのときのボーレートを表示する
initial_flag:
	.ds.b	1			;-i 初期値を使う
quiet_flag:
	.ds.b	1			;-q 設定を表示しない
startup_flag:
	.ds.b	1			;-s 起動時の設定を変更する
buffer:
	.ds.b	1024			;文字列バッファ
	.text

;----------------------------------------------------------------
;引数をコピーする
;	空白を読み飛ばしてから次の空白の手前までコピーする
;	"~"または'~'で囲むと引数に空白を含めることができる
;	""または''と書くと長さが0の引数を与えることができる
;<a0.l:コピー先のバッファの先頭
;<a1.l:コピー元の文字列の先頭
;>d0.l:0=引数がない,1=引数がある
;>a0.l:コピー先の文字列の末尾の0の位置
;>a1.l:コピー元の引数の直後。なければコピー元の文字列の末尾の0の位置
;>eq=引数がない,ne=引数がある
argcpy::
	exg.l	a0,a1
	bsr	nextword		;空白を読み飛ばす
	exg.l	a0,a1
	if	eq			;引数がない
		clr.b	(a0)
		moveq.l	#0,d0
		rts
	endif
	dostart
		if	<cmp.b #'"',d0>,eq	;"~"
			dostart
				move.b	d0,(a0)+		;書き込む
			start
				move.b	(a1)+,d0		;次の文字
				break2	eq			;引数が終わった
			while	<cmp.b #'"',d0>,ne
		elif	<cmp.b #39,d0>,eq	;'~'
			dostart
				move.b	d0,(a0)+		;書き込む
			start
				move.b	(a1)+,d0		;次の文字
				break2	eq			;引数が終わった
			while	<cmp.b #$39,d0>,ne
		else
			move.b	d0,(a0)+		;書き込む
		endif
	start
		move.b	(a1)+,d0		;次の文字
		break	eq			;引数が終わった
		breakand	<cmp.b #9,d0>,hs,<cmp.b #13,d0>,ls	;\t\n\v\f\rならば終了
	while	<cmp.b #' ',d0>,ne	;空白でなければ繰り返す
	subq.l	#1,a1			;進み過ぎた分戻る
	clr.b	(a0)
	moveq.l	#1,d0
	rts

;----------------------------------------------------------------
;改行をコピーする
;<a0.l:コピー先
;>a0.l:コピー先の0の位置
crlf::
	move.b	#13,(a0)+
	move.b	#10,(a0)+
	clr.b	(a0)
	rts

;----------------------------------------------------------------
;16進数の文字を整数に変換する
;<d0.b:文字
;>d0.l:0~16。-1=16進数の文字ではない
;>n:mi=16進数の文字ではない
fromxdigit::
	sub.b	#'0',d0
	blo	1f			;x<0
	sub.b	#('9'+1)-'0',d0
	blo	3f			;0<=x<=9
	subq.b	#'A'-('9'+1),d0
	blo	1f			;9<x<A
	subq.b	#('F'+1)-'A',d0
	blo	2f			;A<=x<=F
	sub.b	#'a'-('F'+1),d0
	blo	1f			;F<x<A
	subq.b	#('f'+1)-'a',d0
	blo	2f			;a<=x<=f
1:	moveq.l	#-1,d0			;x<0||9<x<A||F<x<a||f<x
	rts
2:	addq.b	#6,d0			;A<=x<=F||a<=x<=f
3:	add.b	#10,d0			;0<=x<=9
	ext.w	d0
	ext.l	d0
	rts

;----------------------------------------------------------------
;符号なし整数を16進数4桁の文字列に変換する
;<d0.w:符号なし整数
;<a0.l:バッファ。16進数4桁の文字列の先頭
;>a0.l:16進数4桁の文字列の末尾の0の位置
h4tos::
	push	d1-d2
	moveq.l	#4-1,d1
	for	d1
		rol.w	#4,d0
		moveq.l	#15,d2
		and.w	d0,d2
		move.b	100f(pc,d2.w),(a0)+
	next
	clr.b	(a0)
	pop
	rts

100:	.dc.b	'0123456789ABCDEF'

;----------------------------------------------------------------
;文字の種類を確認する
;<d0.b:文字
;>c:cc=成功,cs=失敗
isgraph::
	gotoand	<cmp.b #'!',d0>,hs,<cmp.b #'~',d0>,ls,2f
	goto	1f
isupper::
	gotoand	<cmp.b #'A',d0>,hs,<cmp.b #'Z',d0>,ls,2f
	goto	1f
isalnum::
	gotoand	<cmp.b #'0',d0>,hs,<cmp.b #'9',d0>,ls,2f
isalpha::
	gotoand	<cmp.b #'A',d0>,hs,<cmp.b #'Z',d0>,ls,2f
islower::
	gotoand	<cmp.b #'a',d0>,hs,<cmp.b #'z',d0>,ls,2f
	goto	1f
isbdigit::
	gotoand	<cmp.b #'0',d0>,hs,<cmp.b #'1',d0>,ls,2f
	goto	1f
isodigit::
	gotoand	<cmp.b #'0',d0>,hs,<cmp.b #'7',d0>,ls,2f
	goto	1f
isxdigit::
	gotoand	<cmp.b #'A',d0>,hs,<cmp.b #'F',d0>,ls,2f
	gotoand	<cmp.b #'a',d0>,hs,<cmp.b #'f',d0>,ls,2f
isdigit::
	gotoand	<cmp.b #'0',d0>,hs,<cmp.b #'9',d0>,ls,2f
	goto	1f
isspace::
	goto	<cmp.b #' ',d0>,eq,2f
	gotoand	<cmp.b #$09,d0>,hs,<cmp.b #$0D,d0>,ls,2f
1:	move.w	#%00001,ccr		;cs=失敗
	rts
2:	move.w	#%00000,ccr		;cc=成功
	rts

;----------------------------------------------------------------
;-more-を挟みながら文字列を表示する
;<a0.l:文字列
more::
	push	d0-d5/a0-a2
;標準入力を確認する
	clr.l	-(sp)			;(0<<16)|0
	DOS	_IOCTRL
	addq.l	#4,sp
;<d0.b:標準入力のFCBフラグ
	and.b	#$81,d0			;キャラクタデバイス、標準入力
	goto	<cmp.b #$81,d0>,ne,90f	;標準入力がリダイレクトされている。moreしない
;標準出力を確認する
	pea.l	1.w			;(0<<16)|1
	DOS	_IOCTRL
	addq.l	#4,sp
;<d0.b:標準出力のFCBフラグ
	and.b	#$82,d0			;キャラクタデバイス、標準出力
	goto	<cmp.b #$82,d0>,ne,90f	;標準出力がリダイレクトされている。moreしない
;CONDRV.SYSを確認する
	move.w	#$0100+_KEY_INIT,-(sp)
	DOS	_INTVCG
	addq.l	#2,sp
	movea.l	d0,a1
	subq.l	#4,a1
	IOCS	_B_LPEEK
	goto	<cmp.l #'hmk*',d0>,eq,90f	;CONDRV.SYSが組み込まれている。moreしない
;画面の大きさを確認する
	moveq.l	#-1,d1
	moveq.l	#-1,d2
	IOCS	_B_CONSOL
;<d2.l:右端の桁座標<<16|下端の行座標
	move.w	d2,d3
	swap.w	d2
	addq.w	#1,d2
;<d2.w:画面の桁数
;<d3.w:下端の行座標。-more-の行を除いた画面の行数
	gotoor	<cmp.w #8,d2>,lo,<tst.w d3>,eq,90f	;画面が狭すぎる。moreしない。タブを含めて1文字以上書けなければならないので8桁x1行が下限
;ページループ
	do
		move.l	#0,d4			;桁座標
		move.l	#0,d5			;行座標
		movea.l	a0,a2			;ページ先頭
	;文字ループ
		do
			movea.l	a0,a1			;文字先頭
			move.b	(a0)+,d0		;1バイト目
			if	eq			;00 終了
				subq.l	#1,a0
				break
			elif	<cmp.b #$09,d0>,eq	;09 タブ
				moveq.l	#7,d1
				and.w	d4,d1
				subq.w	#8,d1
				neg.w	d1		;タブの桁数
			elif	<cmp.b #$0A,d0>,eq	;0A 改行
				moveq.l	#0,d4		;左端へ
				addq.w	#1,d5		;次の行へ
				break	<cmp.w d3,d5>,eq	;下端。ページ終わり
				continue
			elif	<cmp.b #$0C,d0>,eq	;0C 改ページ
				break
			elif	<cmp.b #$1F,d0>,ls	;01-08,0B,0D-1F 無視する
				continue
			else				;20-FF
				do
					moveq.l	#1,d1			;半角の桁数
					break	<tst.b d0>,pl		;20-7F アスキー
					breakand	<cmp.b #$A0,d0>,hs,<cmp.b #$DF,d0>,ls	;A0-DF 半角カタカナ
					addq.l	#1,a0			;2バイト目
					break	<cmp.b #$80,d0>,eq	;8000-80FF 半角ひらがな
					break	<cmp.b #$F0,d0>,hs	;F000-FFFF 1/4角、半角外字
					moveq.l	#2,d1			;全角の桁数
				while	f
			endif
			add.w	d1,d4			;表示した後の桁座標
			if	<cmp.w d2,d4>,hi	;はみ出す
				sub.w	d1,d4			;進み過ぎた分戻る
				movea.l	a1,a0
				addq.w	#1,d5			;次の行へ
				break	<cmp.w d3,d5>,eq	;下端。ページ終わり
				moveq.l	#0,d4			;左端へ
			endif
		while	t
	;1ページ表示する
		move.l	a0,d0			;末尾
		sub.l	a2,d0			;末尾-先頭=長さ
		move.l	d0,-(sp)		;長さ
		move.l	a2,-(sp)		;先頭
		move.w	#1,-(sp)		;標準出力
		DOS	_WRITE
		lea.l	10(sp),sp
	;続きがなければ終了する
		break	<tst.b (a0)>,eq
	;必要ならば改行する
		ifand	<tst.w d4>,ne,<cmp.w d2,d4>,ne	;左端でも右端でもない
			bsr	printcrlf
		endif
	;-more-を表示する
		pea.l	6.w
		pea.l	100f(pc)		;'-more-'
		move.w	#1,-(sp)
		DOS	_WRITE
		lea.l	10(sp),sp
	;キー入力を待つ
		DOS	_GETC
		move.l	d0,d1
	;改行する
		bsr	printcrlf
	whileand	<cmp.b #$1B,d1>,ne,<cmp.b #'Q',d1>,ne,<cmp.b #'q',d1>,ne	;ESCまたはQが押されたときは終了する
99:	pop
	rts

;moreしない
90:	bsr	print
	goto	99b

100:	.dc.b	'-more-'
	.even

;----------------------------------------------------------------
;空白を読み飛ばす
;<a0.l:文字列
;>d0.l:最初の空白以外の文字または0
;>a0.l:最初の空白以外の文字または0の位置
;>z:ne=空白以外の文字がある,eq=空白以外の文字がない
nextword::
	moveq.l	#0,d0
	do
		move.b	(a0)+,d0		;次の文字
		break	eq			;0ならば終了
		redo	<cmp.b #' ',d0>,eq	;' 'ならば繰り返す
	whileand	<cmp.b #9,d0>,hs,<cmp.b #13,d0>,ls	;\t\n\v\f\rならば繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る
	tst.l	d0
	rts

;----------------------------------------------------------------
;文字列を表示する
;<a0.l:文字列
print::
	push	d0
	bsr	strlen
	move.l	d0,-(sp)
	move.l	a0,-(sp)
	move.w	#1,-(sp)
	DOS	_WRITE
	lea.l	(10,sp),sp
	pop
	rts

;----------------------------------------------------------------
;改行を表示する
printcrlf::
	move.l	a0,-(sp)
	lea.l	100f(pc),a0		;13,10
	bsr	print
	movea.l	(sp)+,a0
	rts

100:	.dc.b	13,10,0
	.even

;----------------------------------------------------------------
;16進数の文字列を符号なし整数に変換する
;<a0.l:16進数の文字列。先頭の空白は認めない
;>d0.l:符号なし整数。(csのとき)下位32ビット
;>a0.l:16進数ではない文字または0の位置
;>c:cc=成功,cs=16進数の文字がないまたはオーバーフロー
;>v:(csのとき)vc=16進数の文字がない,vs=オーバーフロー
stoh::
	push	d1-d2/a1
	moveq.l	#0,d1			;符号なし整数
	moveq.l	#0,d2			;オーバーフロー判定用
	movea.l	a0,a1			;開始位置
	dostart
		or.l	d1,d2			;16倍する直前の値のOR
		lsl.l	#4,d1			;16倍して
		or.b	d0,d1			;1桁加える
	start
		move.b	(a0)+,d0		;次の文字
		bsr	fromxdigit
	while	pl			;16進数の文字ならば繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る
	add.l	#$F0000000,d2
	subx.w	d2,d2			;16倍する直前の値のORの上位4ビットが0でないすなわちオーバーフローのとき-1、さもなくば0
	and.w	#%00011,d2		;オーバーフローのときvs,cs、さもなくばvc,cc
	if	<cmpa.l a1,a0>,eq	;進んでいない
		or.w	#%00001,d2		;16進数の文字がないときcs
	endif
	move.l	d1,d0			;符号なし整数
	move.w	d2,ccr
	popm
	rts

;----------------------------------------------------------------
;文字列をコピーする
;<a0.l:コピー先
;<a1.l:コピー元
;>a0.l:コピー先の0の位置
;>a1.l:コピー元の0の次の位置
strcpy::
	do
		move.b	(a1)+,(a0)+
	while	ne			;0でなければ繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る
	rts

;----------------------------------------------------------------
;小文字化しながら文字列比較
;	'['<'A'となることに注意。SJISは正しく比較できないことに注意
;<a0.l:文字列0。引かれる
;<a1.l:文字列1。引く
;>ccr:eq=文字列0==文字列1,lo=文字列0<文字列1,hi=文字列1<文字列0
stricmp::
	push	d0-d1/a0-a1
	do
		move.b	(a0)+,d0
		if	eq
			cmp.b	(a1)+,d0
			break
		endif
		move.b	(a1)+,d1
		ifand	<cmp.b #'A',d0>,hs,<cmp.b #'Z',d0>,ls
			or.b	#$20,d0
		endif
		ifand	<cmp.b #'A',d1>,hs,<cmp.b #'Z',d1>,ls
			or.b	#$20,d1
		endif
		cmp.b	d1,d0
	while	eq
	pop
	rts

;----------------------------------------------------------------
;文字列の長さを数える
;<a0.l:文字列
;>d0.l:長さ
strlen::
	move.l	a0,d0			;d0=先頭
	do
		tst.b (a0)+
	while	ne			;0でなければ繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る。a0=末尾
	exg.l	d0,a0			;d0=末尾,a0=先頭
	sub.l	a0,d0			;d0=末尾-先頭=長さ
	rts

;----------------------------------------------------------------
;小文字にする
;<d0.b:文字
;>d0.b:文字
tolower::
	ifand	<cmp.b #'A',d0>,hs,<cmp.b #'Z',d0>,ls	;大文字
		add.b	#'a'-'A',d0		;小文字にする
	endif
	rts

	.end