;DISK UTILITY -	By Ward Christensen
;DU.ASM	V3.0	EDIT 10
;
;	8/6/78
;ORIGINALLY WRITTEN TO RECONSTRUCT BLOWN
;DISKS ON CBBS VIA REMOTE ACCESS
;
;		----------------
;Sorry for the lack of comments in the code 
;portion of this program - it was just hacked
;together to satisfy my needs, but lots of
;other people found it useful.  Its external
;documentation is good, but its sadly lacking
;comments on the instructions.
;		----------------
;
;	11/12/78 WLC
;ADD LOGIN COMMAND
;
;	11/26/78 WLC
;ADD DISK # TO LOGIN COMMAND
;
;	02/25/79 WLC
;PUT SECTOR READ INTO "S" COMMAND
;
;	10/10/79 WLC
;SAVE REGS IN BIOS CALLS
;TRANSLATE INPUT TO UPPER CASE
;ADD COMMANDS: 	< SAVE SECTOR
;		> RESTORE SECT
;		/ REPEAT
;ALLOW CHANGE FROM-THRU
;
;	01/06/80 WLC
;REWRITE "F" COMMAND
;
;	01/07/79
;ADD VIEW COMMAND
;
;	01/08/80
;REPOSITION AFTER "M" COMMAND
;
CR	EQU	0DH
LF	EQU	0AH
TAB	EQU	09H
;
;Any valid command string may be placed as an
;operand of the original DU command, i.e.:
;
;	DU G0;D;G2;=OK<D><A><1A>;D
;
;Functions supported:
;
;	Tnn	Seek to track nn (no read)
;	Snn	Position to sector nn, and read
;	Gnn	Position to group nn and read.
;	G	Shows current position
;	V	Views the current sector.
;		(assumes ASCII data)
;	Vnn	Views nn sectors
;	Fname	print directory for file "name",
;		then positions to it's directory 
;		sector.
;
;	=string	Ascii search, starting at current
;		sector.  <xx> hex may be imbedded,
;		or used alone:  To find "IN 0FEH":
;		=<db><fe>
;
;	L	Re-logs in the current disk. You may pull
;		out a disk, put in a new, and "L" just
;		to log it in (prevents 	CP/M 1.4
;		from getting R/O errors). (hmmm, on second
;		thought, I'm not doing any BDOS calls
;		anyway, so no R/O errors COULD occur..
;		owell, better safe than sorry)
;
;	Lx	Logs in disk 'x', such as: LB
;
;	D	Dump sector, hex + ASCII
;	A	Dump sector, ASCII only
;	H	Dump sector, hex only
;
;note all dump commands (D, A, H) may be optionally
;	followed by a starting and ending address:
;	D0,7F  is the same as just D
;	D3,5
;	A20,3F
;
;	CHaddr,val,val,val... change hex in sector
;	CAaddr,char string... change ASCII in sector
;		NOTE that <xx> may be hex imbedded
;		in the Ascii:  ca0,OK<d><a><1a>
;
;		----> Use W to write changes to disk.
;		Note that the C command echoes
;		the overlaid data for verification.
;
;	CHaddr-addr,byte
; or	CAaddr-addr,byte	repeats a change
;
;	#	(Used by Ward to set the sector
;		order table to 1,2,3,4,5...
;		for my strange disks)
;
;	+	advance 1 sector (if below track 2,
;		this advances to next numerical, if
;		2 or >, advances based on CP/M's normal
;		sector scrambling algorithm, i.e. so +
;		will get the next logical sector of the file
;
;	-	backs up 1 logical sector
;
;		note + and - may take an amount:
;		for example, +F steps in 15 sectors
;
;	?	Gives command summary
;
;	M	Dumps a map of the group allocations
;		for files.
;	Mn	Shows which file is allocated to
;		group "n".
;
;	R	Reads the sector currently positioned to
;		into memory.  Note R (Read) is implicit in
;		the G, +, and - commands, but N-O-T in the
;		S and T commands (I did it because I was
;		tired of disk reading after T command before
;		I had a chance to issue the S command)
;
;	W	Write back the current sector (N-O-T-E may
;		not be used after an F command, as CP/M was
;		used to find the file in the directory
;
;	X	Exit back to CP/M (Must press return).  Ctl-c
;		was too easy to hit over modem lines, so I
;		decided on 2-byte (X, CR) to exit.
;
;	P	Toggle printer switch on/off
;
;	Z	Sleep - causes the program to pause, such
;		as to look at a dump.  Z is 1 sec.  Znn
;		is nn tenths of a second on a 2 MHz 8080.
;
;	<	Saves current sector in a save buffer
;
;	>	Gets saved buffer.  < and > may be used
;		to move a sector to another place.
;
;	/	Repeats entire command.  Defaults
; or	/nn	to "forever".  NN may be 2 to 254
;
;multiple commands may be separated by ";"
;
;Example: the following commands will erase the
;	b disk directory to all E5's:
;
;	lb			log in b drive
;	g0			position to dir.
;	ch0-7f,e5		fill with e5
;	<			save the sector
;	>;w;+;/16		restore, write, next,
;				repeat 16       
;
;----This could be shortened to:
;
;	lb;g0;ch0-7f,e5;<
;	>;w;+;/16
;
	ORG	100H
	LXI	SP,STACK ;EXITS VIA JMP 0
;SET UP LOCAL JMPS TO BIOS
	LHLD	1	;WARM BOOT POINTER
	LXI	D,3
	DAD	D	
	SHLD	VCONST+1
	DAD	D
	SHLD	VCONIN+1
	DAD	D
	SHLD	VCONOUT+1
	DAD	D	;LIST
	SHLD	VLIST+1
	DAD	D	;PUNCH
	DAD	D	;RDR
	DAD	D
	SHLD	VHOME+1
	DAD	D	;SEL DISK
	DAD	D
	SHLD	VSETTRK+1
	DAD	D
	SHLD	VSETSEC+1
	DAD	D
	SHLD	VSETDMA+1
	DAD	D
	SHLD	VREAD+1
	DAD	D
	SHLD	VWRITE+1
	CALL	ILPRT
	DB	'DISK UTILITY (DU) V3.0 01/07/80',CR,LF
	DB	CR,LF,'Type ? for help'
	DB	CR,LF,'Type X to exit'
	DB	CR,LF,0
	LXI	H,80H	;TO INPUT BUFF
	MOV	A,M
	ORA	A
	JZ	PROMPTR	;NO COMMAND
;
;GOT INITIAL COMMAND, SET IT UP
;
	MOV	B,A	;SAVE LENGTH
	DCR	B
	JZ	PROMPTR
	LXI	D,INBUF
	INX	H	;SKIP LEN
	INX	H	;SKIP ' '
	CALL	MOVE
	MVI	A,CR
	STAX	D
	LXI	H,INBUF
	JMP	PROMPTI
;
PROMPTR	CALL	RDBUF
PROMPTI	MVI	A,255
	STA	TOGO	;LOOP COUNT FOR "/"
PROMPT	LXI	SP,STACK
	XRA	A	;ZERO 2-UP PRINT
	STA	TWOUP	;..SWITCH
	MVI	A,1
	STA	FTSW	;TELL SEARCH NOT TO INCR
	PUSH	H
	LXI	H,100H
	SHLD	BUFAD	;FOR RDBYTE
	POP	H
	CALL	CTLCS	;ABORT?
	JZ	PROMPTR	;..YES, READ BUFFER
;DO WE HAVE TO POSITION IN DIRECTORY AFTER FIND?
	LDA	FINDFLG
	ORA	A
	JNZ	POSDIR	;POSITION IN DIRECTORY
	MOV	A,M
	CPI	CR
	JZ	PROMPTR
	CPI	';'	;LOGICAL CR?
	INX	H
	JZ	PROMPT
	CALL	UPCASE
	STA	DUMTYPE	;TYPE OF DUMP (A,D,H)
	CPI	'!'	! JZ WARDSK ;<----DON'T USE
	CPI	'+'	! JZ PLUS
	CPI	'-'	! JZ MINUS
	CPI	'='	! JZ SEARCH
	CPI	'<'	! JZ SAVE
	CPI	'>'	! JZ RESTORE
	CPI	'?'	! JZ HELP
	CPI	'A'	! JZ DUMP
	CPI	'C'	! JZ CHG
	CPI	'D'	! JZ DUMP
	CPI	'F'	! JZ POSFIL
	CPI	'G'	! JZ POS
	CPI	'H'	! JZ DUMP
	CPI	'L'	! JZ LOGIN
	CPI	'M'	! JZ MAP
	CPI	'P'	! JZ PRINTFF
	CPI	'R'	! JZ DOREAD
	CPI	'S'	! JZ POS
	CPI	'T'	! JZ POS
	CPI	'V'	! JZ VIEW
	CPI	'W'	! JZ DOWRITE
	CPI	'X'	! JZ 0
	CPI	'Z'	! JZ SLEEP
	CPI	'/'	! JZ REPEAT
;
WHAT	CALL	ILPRT
	DB	'?',0
	JMP	PROMPTR
;
;REPEAT BUFFER CONTENTS
;
REPEAT	CALL	DECIN	;NN SPECIFIED?
	MOV	A,E
	ORA	A
	JZ	NNN	;NO.
	LDA	TOGO	;FIRST TIME?
	CPI	0FFH	;WAS IT 0FFH?
	JNZ	NNN	;NO:  COUNTING
	MOV	A,E	;GET COUNT
	STA	TOGO	;SET COUNT
NNN	LXI	H,INBUF	;READY TO REPEAT
	LDA	TOGO
	CPI	0FFH
	JZ	PROMPT	;CONTINUOUS
	DCR	A	;COUNT DOWN
	STA	TOGO
	JNZ	PROMPT
	JMP	PROMPTR	;RESET
;
;TOGGLE PRINT FLAG
;
PRINTFF	LDA	PFLAG
	XRI	1
	STA	PFLAG
	JMP	PROMPT
;
;SLEEP ROUTINE, IN TENTHS OF A SEC
;
SLEEP	CALL	HEXIN	;GET COUNT IF ANY
	MOV	A,E	;ANY?
	ORA	A
	JNZ	SLEEPLP
	MVI	E,10
SLEEPLP	LXI	B,8000	;APPROX .1 SEC @ 2MHz
SLEEP2	DCX	B
	MOV	A,B
	ORA	C
	JNZ	SLEEP2
	PUSH	D
	CALL	CTLCS
	POP	D
	JZ	PROMPTR
	DCR	E
	JNZ	SLEEPLP
	JMP	PROMPT
;
;CHECK FOR CONTROL-C OR S
;
CTLCS	CALL	CONST
	INR	A
	RNZ		;NO CHAR
	CALL	CONIN
	ANI	1FH	;ALLOW ASCII
	CPI	'S'-40H
	CZ	CONIN
	CPI	'C'-40H
	RET		;0 SET IF CTL-C
;
LOGIN	MVI	C,RESETDK
	PUSH	H
	CALL	BDOS
	POP	H
	MOV	A,M	;DISK REQ?
	LXI	D,0
	CPI	CR
	JZ	LGNODK
	CPI	';'
	JZ	LGNODK
	CALL	UPCASE
	INX	H
	SUI	'A'
	MOV	E,A
LGNODK	MVI	C,SELDK
	PUSH	H
	CALL	BDOS
	POP	H
	CALL	NOWRITE
	JMP	PROMPT
;
;READ IN THE DISK DIRECTORY
;
READDIR	PUSH	H
	CALL	NOWRITE	;POSITIONING LOST
	MVI	A,2
	STA	CURTRK
	MVI	A,1
	STA	CURSEC
	MVI	B,16	;# OF SECTORS
	LXI	D,DIRECT ;DMA ADDR
RDIRLP	PUSH	B
	PUSH	D
	MOV	B,D
	MOV	C,E
	CALL	VSETDMA
	LDA	CURTRK
	CALL	SETTRK
	LDA	CURSEC
	CALL	SETSEC
	CALL	READ
	CALL	NEXTSEC
	POP	D
	POP	B
	LXI	H,80H
	DAD	D
	XCHG
	DCR	B
	JNZ	RDIRLP
	LXI	B,80H
	CALL	VSETDMA
	POP	H
	RET
;
;MAP THE DIRECTORY
;
MAP	CALL	READDIR	;READ IN DIRECTORY
	MVI	C,2	;DFLT START
	CALL	HEXIN
	PUSH	H	;SAVE INBUF PTR
	MOV	A,E	;GET START
	ORA	A	;NOTHING?
	JZ	MAPDF	;..YES, DFLT
	MOV	C,E
MAPDF	MOV	A,C
	CALL	HEX
	MVI	A,'-'
	CALL	TYPE
	CALL	GETGRP	;GET GRP(C) TO HL
MAPCONT	INR	C	;NEXT GRP
	JZ	MAPEND	;DONE
	PUSH	H
	CALL	GETGRP	;GET ANOTHER
	POP	D	;SEE IF SAME
	CALL	CTLCS
	JZ	MAPEND2
	MOV	A,D
	CMP	H
	JNZ	MAPDIFF
	MOV	A,E
	CMP	L
	JNZ	MAPDIFF
;SAME, CONTINUE
	JMP	MAPCONT
;
;DIFFERENT FILE ENCOUNTERED
;
MAPDIFF	MOV	A,C
	DCR	A
	CALL	HEX
	XCHG
	CALL	MAPNAME
	JMP	MAPDF
;
;END
;
MAPEND	MOV	A,C	;GET LAST
	DCR	A
	CALL	HEX
	CALL	MAPNAME
	POP	H
	CALL	CRLF
;
;END OF MAP - REPOSITION TO PREVIOUS GROUP
;
MAPEND2	LDA	GROUP
	PUSH	H
	MOV	L,A
	JMP	POSGRP2
;
;PRINT FILE NAME POINTED TO BY HL
;
MAPNAME	CALL	SPACE
	MOV	A,H
	ORA	L	;NONE?
	JZ	NONAME
	MOV	A,M	;SEE IF ALLOC
	ORA	A	;ZERO?
	MVI	A,' '
	JZ	MAPNSP1
	MVI	A,'('
MAPNSP1	CALL	TYPE
	PUSH	H	;SAVE POINTER
	INX	H	;SKIP ALLOC BYTE
	MVI	B,8
	CALL	MAPN2
	MVI	A,'.'
	CALL	TYPE
	MVI	B,3
	CALL	MAPN2
	CALL	SPACE
	MOV	A,M	;GET EXT
	ORI	'0'
	CALL	TYPE
	POP	H
	MOV	A,M
	ORA	A
	MVI	A,' '
	JZ	MAPNSP2
	MVI	A,')'
MAPNSP2	CALL	TYPE	;")" IF ERASED FILE
	LDA	TWOUP
	XRI	1
	STA	TWOUP
	JZ	CRLF
	JMP	DELIM
;
NONAME	CALL	ILPRT
	DB	'++FREE++        ',0
	LDA	TWOUP
	XRI	1
	STA	TWOUP
	JZ	CRLF
DELIM	MVI	A,':'
	JMP	TYPE
;
;PRINT NAME, LENGTH IN B
;
MAPN2	MOV	A,M
	INX	H
	CPI	' '	;PRINTABLE?
	JC	MAPN2H	;..NO, IN HEX
	CPI	7FH	
	JC	MAPN2A
MAPN2H	CALL	BHEX
	JMP	MAPN2Z
MAPN2A	CALL	TYPE
MAPN2Z	DCR	B
	JNZ	MAPN2
	RET
;
;FIND WHICH FILE GROUP(C) BELONGS TO
;
GETGRP	LXI	H,DIRECT
	MVI	A,64	;# OF FILES
	STA	FILECT
GETGLP	PUSH	H	;SAVE POINTER
	LXI	D,15	;DISP TO LENGTH
	DAD	D
	MOV	A,M	;GET LENGTH
	ORA	A	;ZERO?
	JZ	GETGNF	;NO FILE
	CPI	0E5H	;UNUSED, FOMATTED DISK?
	JZ	GETGNF
	MOV	B,A	;SAVE COUNT
	DCR	B	;ALLOW JP BELOW
GETGL2	INX	H	;TO NEXT
	MOV	A,M	;GET GRP
	CMP	C	;CORRECT ONE?
	JZ	GETGOT	;YES, GOT IT.
	MOV	A,B	;GET REC COUNT
	SUI	8
	MOV	B,A
	JP	GETGL2
;NO FILE
GETGNF	POP	H
	LXI	D,32
	DAD	D	;TO NEXT ENTRY
	LDA	FILECT
	DCR	A
	STA	FILECT
	JNZ	GETGLP	;MORE?
	LXI	H,0	;NO, NOT FOUND
	RET
;
;GOT THE FILE
;
GETGOT	POP	H	;POINT TO NAME
	RET
;
;SAVE THE CURRENT SECTOR
;
SAVE	LDA	WRFLG
	ORA	A
	JZ	BADW	;NONE TO SAVE
	PUSH	H
	LXI	H,80H
	LXI	D,SAVEBUF
	MVI	B,128
	CALL	MOVE
	MVI	A,1	;..SHOW
	STA	SAVEFLG	;..SAVED EXISTS
	POP	H
	JMP	PROMPT
;
;RESTORE THE CURRENT SECTOR
;
RESTORE	LDA	SAVEFLG
	ORA	A
	JZ	NOSAVE ;NONE TO SAVE
	PUSH	H
	LXI	H,SAVEBUF
	LXI	D,80H
	MVI	B,128
	CALL	MOVE
	POP	H
	JMP	PROMPT
;
NOSAVE	CALL	ILPRT
	DB	'++NO "<" SAVE COMMAND ISSUED'
	DB	CR,LF,0
	JMP	PROMPTR
;
;MOVE (HL) TO (DE) LENGTH IN B
;
MOVE	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVE
	RET
;
NOWRITE	XRA	A	;GET 0
	STA	WRFLG	;CAN'T WRITE NOW
	RET
;
;NO MATCH IN SEARCH, TRY NEXT CHAR
;
SRNOMAT	POP	H
	CALL	CTLCS	;ABORT?
	JNZ	SEARCH	;..YES
	LXI	H,INBUF
	MVI	M,CR
	JMP	CALCGRP	;SHOW WHERE STOPPED
;
;SEARCH FOR CHARACTER STRING
;
SEARCH	PUSH	H	;SAVE STRING POINTER
SRCHL	CALL	RDBYTE	;GET A BYTE
	PUSH	PSW
	CALL	GETVAL	;GET SEARCH VALUE
	MOV	B,A
	POP	PSW
	CMP	B	;MATCH?
	JNZ	SRNOMAT	;NO MATCH
	INX	H
	MOV	A,M	;DONE?
	CPI	CR
	JZ	SREQU
	CPI	';'
	JNZ	SRCHL
;GOT MATCH
SREQU	CALL	ILPRT
	DB	'= AT ',0
	LDA	BUFAD
	ANI	7FH
	CALL	HEX
	CALL	CRLF
	JMP	CALCGRP
;
;GET VALUE FROM INPUT BUFFER
;
GETVAL	MOV	A,M
	CPI	'<'	;HEX ESCAPE?
	RNZ		;NO, RETURN
;"<<" MEANS ONE "<"
	INX	H
	MOV	A,M
	CPI	'<'
	RZ
;GOT HEX
	PUSH	D
	CALL	HEXIN	;GET VALUE
	CPI	'>'	;PROPER DELIM?
	MOV	A,E	;GET VALUE
	POP	D
	JNZ	WHAT	;ERROR
	RET
;
;READ A BYTE AT A TIME
;
RDBYTE	PUSH	H
	LDA	FTSW	;FIRST READ?
	ORA	A
	JNZ	READ1
	LHLD	BUFAD
	MOV	A,H
	ORA	A	;AT 100?
	JZ	NORD	;NO, NO READ
;HAVE TO READ
	CALL	NEXTSEC
READ1	XRA	A
	STA	FTSW	;NOT FIRST READ
	LDA	CURSEC
	CALL	SETSEC
	LDA	CURTRK
	CALL	SETTRK
	CALL	READ
	CALL	CALCSUB
	LXI	H,80H
NORD	MOV	A,M
	INX	H
	SHLD	BUFAD
	POP	H
	RET
;
;VIEW THE FILE IN ASCII STARTING AT
;CURRENT SECTOR, STEPPING THRU THE DISK
;
VIEW	LDA	WRFLG
	ORA	A
	JZ	BADDMP
	CALL	HEXIN	;GET DISPL IF ANY
	PUSH	H
	MOV	A,E
	ORA	A
	JNZ	VIEWLP
	INR	E	;DFLT=1
VIEWLP	LXI	H,80H	;TO DATA
VIEWCHR	CALL	CTLCS
	JZ	VIEWEND
	MOV	A,M
	CPI	1AH
	JZ	VIEWEOF
	CALL	TYPE
	INR	L
	JNZ	VIEWCHR
	DCR	E
	JZ	VIEWEND
	PUSH	D	;SAVE COUNT
	CALL	NEXTSEC
	LDA	CURSEC
	CALL	SETSEC	
	LDA	CURTRK
	CALL	SETTRK
	CALL	READ
	POP	D	;RESTORE COUNT
	JMP	VIEWLP
;
VIEWEOF	CALL	ILPRT
	DB	CR,LF,TAB,'++EOF++',CR,LF,0
;
VIEWEND	POP	H
	CALL	CRLF
	JMP	CALCGRP
;
;DUMP IN HEX OR ASCII
;
DUMP	LDA	WRFLG
	ORA	A
	JNZ	DUMPOK
	CALL	ILPRT
BADDMP	DB	'++Can''t dump, no sector read.',CR,LF,0
EXPL	CALL	ILPRT
	DB	'Use G command following F,',CR,LF
	DB	'or R or S following T',CR,LF,0
	JMP	PROMPTR
;
DUMPOK	MOV	A,M
	CPI	';'
	JZ	DUMPDF	;DFLT
	CPI	CR
	JNZ	DUMPNDF
;USE DEFAULT
DUMPDF	LXI	B,80H
	LXI	D,0FFH
	JMP	DUMP1
DUMPNDF	CALL	DISP
	MOV	B,D
	MOV	C,E
	CPI	CR
	JZ	DUMP1
	CPI	';'
	JZ	DUMP1
	INX	H	;SKIP ','
	CALL	DISP
;
;BC = START, DE = END
;
DUMP1	PUSH	H	;SAVE COMMAND POINTER
	MOV	H,B
	MOV	L,C
DUMPLP	MOV	A,L
	ANI	7FH
	CALL	HEX
	CALL	SPACE
	CALL	SPACE
	LDA	DUMTYPE
	CPI	'A'
	JZ	DUMPAS
	PUSH	H	;SAVE START
DHEX	MOV	A,M
	CALL	HEX
	MOV	A,L
	ANI	3
	CPI	3
	CZ	SPACE
	MOV	A,L
	ANI	7
	CPI	7
	CZ	SPACE
	MOV	A,E
	CMP	L
	JZ	DPOP
	INX	H
	MOV	A,L
	ANI	0FH
	JNZ	DHEX
DPOP	CALL	CTLCS
	JZ	PROMPTR
	LDA	DUMTYPE
	CPI	'H'
	JZ	DNOAS	;HEX ONLY
	POP	H	;GET START ADDR
DUMPAS	CALL	ASTER
DCHR	MOV	A,M
	CPI	' '
	JC	DPER
	CPI	7FH
	JC	DOK
DPER	MVI	A,'.'
DOK	CALL	TYPE
	MOV	A,E
	CMP	L
	JZ	DEND
	INX	H
	MOV	A,L
	ANI	0FH
	JNZ	DCHR
DEND	CALL	ASTER
	CALL	CRLF
	PUSH	D
	CALL	CTLCS
	POP	D
	JZ	PROMPTR
	MOV	A,E
	CMP	L
	JNZ	DUMPLP
	POP	H
	JMP	PROMPT
;
DNOAS	POP	B
	CALL	CRLF
	MOV	A,E
	CMP	L
	JNZ	DUMPLP
	POP	H
	JMP	PROMPT
;
;POSITION
;
POS	PUSH	PSW
	MOV	A,M
	CPI	';'
	JZ	POSINQ
	CPI	CR
	JNZ	POSOK
POSINQ	POP	PSW
	JMP	INQ
;
POSOK	CALL	HEXIN
	POP	PSW
	CPI	'T'
	JZ	POSTRK
	CPI	'S'
	JZ	POSSEC
	CPI	'G'
	JZ	POSGRP
	JMP	WHAT
;
POSTRK	MOV	A,E
	CALL	SETTRK
	CALL	NOWRITE	;TRACK DOESN'T READ
	JMP	CALCGRP
;
POSSEC	MOV	A,E
	ORA	A
	JZ	WHAT
	CPI	27
	JNC	WHAT
	CALL	SETSEC
	CALL	READ
;
CALCGRP	CALL	CALCSUB
	JMP	INQ
;
CALCSUB	PUSH	H
	LDA	CURTRK
	SUI	2	;GRP 0 IS TRK 2
	MOV	L,A
	MVI	H,0
	MOV	D,H
	MOV	E,L
	DAD	H	;X2
	DAD	D	;X3
	DAD	H	;X6
	DAD	H	;X12
	DAD	D	;X13
	DAD	H	;X26
	LDA	CURSEC
	DCR	A
	ADD	L
	MOV	L,A
	MOV	A,H
	ACI	0
	MOV	H,A
	MOV	A,L
	ANI	7
	STA	GRPDISP
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	MOV	A,H
	STA	GROUP
	POP	H
	RET
;
;POSITION IN THE DIRECTORY AFTER A FIND
;
POSDIR	PUSH	H	;SAVE INBUF
	XRA	A
	STA	FINDFLG	;CANCEL POS REQ
	LDA	DIRPOS	;GET POSITION
	RAR
	RAR
	PUSH	PSW
	ANI	7	;GET GRP DISPLACEMENT
	STA	GRPDISP
	POP	PSW
	RAR
	RAR
	RAR
	ANI	1	;GET GROUP
	STA	GROUP
	MOV	L,A	;SETUP FOR POSGRP2
	JMP	POSGRP2	;POSITION TO IT
;
POSGRP	MOV	A,E
	STA	GROUP
	XRA	A
	STA	GRPDISP
	PUSH	H
	MOV	L,E	;MULTIPLY
POSGRP2	MVI	H,0	;BY 8
	DAD	H
	DAD	H
	DAD	H
	LDA	GRPDISP	;MAY BE >0 IF "F" CMD.
	ADD	L	;CAN'T CARRY
	MOV	L,A
;DIVIDE BY 26, QUOTIENT = TRK, REMAINDER = SECTOR
	LXI	D,-26
	MVI	B,0	;TRK
DIVLP	INR	B
	DAD	D
	JC	DIVLP
	DCR	B
	LXI	D,26
	DAD	D
	MOV	A,B
	ADI	2	;GROUP 0 IS TRK 2
	CALL	SETTRK
	MOV	A,L
	INR	A
	CALL	SETSEC
	CALL	READ
	POP	H
	JMP	INQ
;
POSFIL	CALL	NOWRITE
	MVI	A,1
	STA	FINDFLG	;SO WE POSITION LATER
	LXI	D,FCB
	XRA	A	;LOGGED IN DISK
	STAX	D
	INX	D
	MVI	B,8
	CALL	MVNAME
	MVI	B,3
	CALL	MVNAME
	LXI	D,FCB
	MVI	C,SRCHF
	PUSH	H
	CALL	BDOS
	INR	A
	JNZ	FLOK
	STA	DIRPOS	;GRP 0 IF NOT FOUND
	CALL	ILPRT
	DB	'++FILE NOT FOUND',CR,LF,0
	POP	H
	JMP	PROMPT
;
FLOK	DCR	A
	STA	DIRPOS	;SAVE POS. IN DIR
	ANI	3
	MOV	L,A
	MVI	H,0
	DAD	H	;X32 BYTES/ENTRY
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	LXI	D,80H
	DAD	D	;HL POINTS TO ENTRY
	LXI	D,32
	XCHG
	DAD	D
	XCHG
	MVI	A,'D'
	STA	DUMTYPE
	JMP	DUMPLP	;WHICH POPS H
;
MVNAME	MOV	A,M
	CPI	'.'
	JZ	MVIPAD
	CPI	CR
	JZ	PAD
	CPI	';'
	JZ	PAD
	CALL	UPCASE
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MVNAME
	MOV	A,M
	CPI	CR
	RZ
	CPI	';'
	RZ
	INX	H
	CPI	'.'
	RZ
	JMP	WHAT
;
MVIPAD	INX	H
;
PAD	MVI	A,' '
	STAX	D
	INX	D
	DCR	B
	JNZ	PAD
	RET
;
PLUS	LXI	D,1	;DFLT TO 1 SECT
	MOV	A,M	;GET NEXT CHAR
	CPI	CR	;CR?
	JZ	PLUSGO	;..YES, DFLT TO 1
	CPI	';'
	JZ	PLUSGO
	CALL	HEXIN	;GET #
	MOV	A,E
	ORA	A
	JZ	WHAT
PLUSGO	CALL	NEXTSEC
	DCR	E	;MORE TO GO?
	JNZ	PLUSGO	;..YES
;
;OK, INCREMENTED TO SECTOR.  SETUP AND READ
;
PLUSMI	LDA	CURSEC
	CALL	SETSEC	
	LDA	CURTRK
	CALL	SETTRK
	CALL	READ
	JMP	CALCGRP
;
MINUS	LXI	D,1	;SET DFLT
	MOV	A,M	;GET CHAR
	CPI	CR	;CR?
	JZ	MINGO	;..YES, DFLT=1
	CPI	';'
	JZ	MINGO
	CALL	HEXIN	;..NO, GET ##
	MOV	A,E
	ORA	A
	JZ	WHAT
MINGO	LDA	CURSEC	;GET CURR
	DCR	A	;BACK UP
	JNZ	MINOK	;TO 0?
	LDA	CURTRK	;..YES, BACK..
	DCR	A	;..UP 1..
	STA	CURTRK	;..TRACK
	MVI	A,26	;
MINOK	STA	CURSEC
	DCR	E
	JNZ	MINGO
	JMP	PLUSMI
;
;GO TO NEXT SECTOR
;
NEXTSEC	LDA	CURSEC	;GET CURRENT
	INR	A	;BUMP IT
	CPI	27	;NEXT TRACK?
	JNZ	NEXTOK	;NO, CONI
	LDA	CURTRK	;BUMP..
	INR	A	;..CURR..
	STA	CURTRK	;..TRK
	MVI	A,1	;SECT=1
NEXTOK	STA	CURSEC
	RET
;
;TELL WHAT GRP, DISPLACEMENT, TRK, SECT, PHY SECT
;
INQ	CALL	INQSUB
	JMP	PROMPT
;
;POSITION INQUIRY SUBROUTINE
;	EXECUTED VIA: G S OR T (WITH NO OPERANDS)
;
INQSUB	LDA	CURTRK
	CPI	2
	JC	NOGRP
	CALL	ILPRT
	DB	'G=',0
	LDA	GROUP
	CALL	HEX
	MVI	A,':'
	CALL	TYPE
	LDA	GRPDISP
	ORI	'0'
	CALL	TYPE
	MVI	A,','
	CALL	TYPE
NOGRP	CALL	ILPRT
	DB	' T=',0
	LDA	CURTRK
	CALL	HEX
	CALL	ILPRT
	DB	', S=',0
	LDA	CURSEC
	CALL	HEX
	CALL	ILPRT
	DB	', PS=',0
	LDA	PHYSEC
	CALL	HEX
	CALL	CRLF
	RET
;
CHG	MOV	A,M	;GET TYPE (HEX, ASCII)
	CALL	UPCASE
	PUSH	PSW	;SAVE "H" OR "A"
	INX	H
	CALL	DISP	;GET, VALIDATE DISP TO DE
	INX	H
	LXI	B,0	;SHOW NO 'THRU' ADDR
	CPI	'-'	;TEST DELIM FR. DISP
	JNZ	CHGNTH	;NO THRU
	PUSH	D	;SAVE FROM
	CALL	DISP	;GET THRU
	MOV	B,D
	MOV	C,E	;BC = THRU
	POP	D	;GET FROM
	JMP	CHGAH
CHGNTH	CPI	','
	JNZ	WHAT
CHGAH	POP	PSW
	CPI	'H'
	JZ	CHGHEX
	CPI	'A'
	JNZ	WHAT
;CHANGE ASCII
CHGALP	MOV	A,M
	CPI	CR
	JZ	PROMPT
	CPI	';'
	JZ	PROMPT
	LDAX	D
	CPI	' '
	JC	CHGAHX
	CPI	7FH
	JNC	CHGAHX
	JMP	CHGA2
CHGAHX	CALL	BHEX
	JMP	CHGA3
CHGA2	CALL	TYPE
CHGA3	CALL	GETVAL	;ASCII OR <HEX>
	STAX	D	;UPDATE CHAR
	INX	H	;TO NEXT INPUT CHAR
;SEE IF 'THRU' REQUESTED
	MOV	A,C
	ORA	A
	JZ	CHGANTH
	CMP	E	;DONE?
	JZ	PROMPT
	DCX	H	;..NO: MORE.
CHGANTH	INR	E
	JNZ	CHGALP
	MOV	A,M
	CPI	CR
	JZ	PROMPT
	CPI	';'
	JZ	PROMPT
	JMP	WHAT
;
;CHANGE HEX
;
CHGHCOM	INX	H
CHGHEX	MOV	A,M
	CPI	CR
	JZ	PROMPT
	CPI	';'
	JZ	PROMPT
	CPI	','	;DELIM?
	JZ	CHGHCOM
	PUSH	D
	SHLD	HEXAD	;IN CASE 'THRU'
	CALL	HEXIN	;POSITIONS TO DELIM
	MOV	A,E	;GET VALUE
	POP	D	;..ADDR
	PUSH	PSW	;SAVE VALUE
	LDAX	D	;GET OLD
	CALL	HEX	;ECHO IN HEX
	POP	PSW	;GET NEW
	STAX	D	;SAVE NEW
;
	MOV	A,C	;SEE IF 'THRU'
	ORA	A
	JZ	CHGHNTH	;..NO.
	CMP	E	;..YES, DONE?
	JZ	PROMPT
	LHLD	HEXAD	;..NO: MORE
CHGHNTH	INR	E
	JNZ	CHGHEX
	MOV	A,M
	CPI	CR
	JZ	PROMPT
	CPI	';'
	JZ	PROMPT
	JMP	WHAT
;
DOREAD	CALL	READ
	JMP	PROMPT
;
DOWRITE	CALL	WRITE
	JMP	PROMPT
;
BHEX	PUSH	PSW
	MVI	A,'<'
	CALL	TYPE
	POP	PSW
	CALL	HEX
	MVI	A,'>'
	CALL	TYPE
	RET
;
HEX	PUSH	PSW
	RAR
	RAR
	RAR
	RAR
	CALL	NIBBL
	POP	PSW
NIBBL	ANI	0FH
	CPI	10
	JC	HEXNU
	ADI	7
HEXNU	ADI	'0'
	JMP	TYPE
;
SPACE	MVI	A,' '
	JMP	TYPE
ASTER	MVI	A,'*'
	JMP	TYPE
;
ILPRT	XTHL
ILPLP	CALL	CTLCS	;ABORT?
	JZ	PROMPTR
	MOV	A,M
	CALL	TYPE
	INX	H
	MOV	A,M
	ORA	A
	JNZ	ILPLP
	INX	H
	XTHL
	RET
;
;DISP CALLS HEXIN, AND VALIDATES A SECTOR
;DISPLACEMENT, THEN CONVERTS IT TO AN ADDRESS
;
DISP	CALL	HEXIN
	PUSH	PSW	;SAVE DELIMITER
	MOV	A,D
	ORA	A
	JNZ	BADISP
	MOV	A,E
	ORA	A
	JM	BADISP
	ADI	80H	;TO POINT TO BUFFER AT 80
	MOV	E,A
	POP	PSW	;GET DELIM
	RET
;
BADISP	CALL	ILPRT
	DB	'++BAD DISPLACEMENT (NOT 0-7F)'
	DB	CR,LF,0
	JMP	PROMPTR
;
HEXIN	LXI	D,0
	MOV	A,M
	CPI	'#'	;DECIMAL?
	JZ	HDIN	;MAKE DECIMAL
HINLP	MOV	A,M
	CALL	UPCASE
	CPI	CR
	RZ
	CPI	';'
	RZ
	CPI	','
	RZ
	CPI	'-'	;'THRU'?
	RZ
	CPI	'>'
	RZ
	INX	H
	CPI	'0'
	JC	WHAT
	CPI	'9'+1
	JC	HINNUM
	CPI	'A'
	JC	WHAT
	CPI	'F'+1
	JNC	WHAT
	SUI	7
HINNUM	SUI	'0'
	XCHG
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	ADD	L
	MOV	L,A
	XCHG
	JMP	HINLP
;
HDIN	INX	H	;SKIP '.'
DECIN	LXI	D,0
DINLP	MOV	A,M
	CALL	UPCASE
	CPI	CR
	RZ
	CPI	';'
	RZ
	CPI	','
	RZ
	CPI	'-'	;'THRU'?
	RZ
	INX	H
	CPI	'0'
	JC	WHAT
	CPI	'9'+1
	JNC	WHAT
	SUI	'0'
	PUSH	H
	MOV	H,D
	MOV	L,E
	DAD	H	;X2
	DAD	H	;X4
	DAD	D	;X5
	DAD	H	;X10
	ADD	L
	MOV	L,A
	MOV	A,H
	ACI	0
	MOV	H,A
	XCHG
	POP	H
	JMP	DINLP
;
;READ IN A CONSOLE BUFFER FULL
;
RDBUF	CALL	ILPRT
	DB	CR,LF,':',0
	LXI	H,INBUF
	MVI	B,0
RDBLP	CALL	CONIN
	MOV	C,A	;SAVE FOR BS TEST
	CPI	'U'-40H
	JZ	RDCTLU
	CPI	CR
	JZ	RDCR
	CPI	8
	JZ	RDBS
	CPI	7FH
	JZ	RDBS
	CPI	'R'-40H
	JZ	RDCTLR
	MOV	M,A
	INX	H
	INR	B
	JM	FULL
	CALL	TYPE
	JMP	RDBLP
;
FULL	DCR	B
	DCX	H
	MVI	A,7	;'DING'
	CALL	TYPE
	JMP	RDBLP
;
;GOT CR
;
RDCR	MOV	M,A	;SAVE IT
	CALL	TYPE	;ECHO IT
	MVI	A,LF	;ECHO..
	CALL	TYPE	;..LF
	LXI	H,INBUF
	RET
;
;GOT DELETE OR BS, ECHO IF BS
;
RDBS	XRA	A	;AT FRONT..
	ORA	B	;..OF LINE?
	JZ	RDCTLU	;..YES, ECHO ^U
	DCX	H
	DCR	B
	MOV	A,C
	CPI	8	;BS?
	JZ	BACKUP	;ECHO THE BS
	MOV	A,M	;ECHO..
	CALL	TYPE	;..DELETED CHAR
	JMP	RDBLP
;
BACKUP	MVI	A,8
	CALL	TYPE
	JMP	RDBLP
;
;GOT CTL-R, RETYPE
;
RDCTLR	MVI	M,CR
	CALL	CRLF
	LXI	H,INBUF
	MVI	B,0
RDCRL	MOV	A,M
	CPI	CR
	JZ	RDBLP
	CALL	TYPE
	INR	B
	INX	H
	JMP	RDCRL
;
;GOT CTL-U OR BACKUP TO BEG. OF LINE.
;
RDCTLU	MVI	A,'^'
	CALL	TYPE
	MVI	A,'U'
	CALL	TYPE
	JMP	RDBUF
;
CRLF	MVI	A,CR
	CALL	TYPE
	MVI	A,LF
	JMP	TYPE
;
UPCASE	CPI	60H
	RC
	ANI	5FH	;MAKE UPPER CASE
	RET
;
CONST	PUSH	B
	PUSH	D
	PUSH	H
VCONST	CALL	$-$
	POP	H
	POP	D
	POP	B
	RET
;
CONIN	PUSH	B
	PUSH	D
	PUSH	H
VCONIN	CALL	$-$
	POP	H
	POP	D
	POP	B
	RET
;
;CONSOLE OUT WITH TAB EXPANSION
;
TYPE	PUSH	B
	PUSH	D
	PUSH	H
	MOV	C,A	;FOR OUTPUT ROUTINE
	CPI	TAB
	JNZ	VCONOUT
TYPETAB	MVI	A,' '
	CALL	TYPE
	LDA	TABCOL
	ANI	7
	JNZ	TYPETAB
	JMP	TYPERET
;
VCONOUT	CALL	$-$	;ADDR FILLED IN BY 'INIT'
;
;UPDATE COLUMN USED IN TAB EXPANSION
;
	MOV	A,C	;GET CHAR
	CPI	CR
	JNZ	TYPENCR
	MVI	A,0
	STA	TABCOL
	JMP	TYPELST
;
TYPENCR	CPI	' '	;CTL CHAR?
	JC	TYPERET	;..NO CHANGE IN COL
	LDA	TABCOL
	INR	A
	STA	TABCOL
TYPELST	LDA	PFLAG
	ANI	1
	CNZ	LIST	;FROM C REG.
TYPERET	POP	H
	POP	D
	POP	B
	RET
;
LIST:			;TYPE SAVED REGS
VLIST	JMP	$-$
;
HOME	PUSH	H
VHOME	CALL	$-$
	POP	H
	RET
;
SETTRK	CPI	77
	JC	TRKOK
	CALL	ILPRT
	DB	'++not in tracks 0-76++'
	DB	CR,LF,0
	CALL	NOWRITE
	JMP	PROMPTR
;
TRKOK	STA	CURTRK
	MOV	C,A
	PUSH	H
VSETTRK	CALL	$-$
	POP	H
	RET
;
SETSEC	STA	CURSEC	;LOGICAL
	MOV	C,A
	LDA	CURTRK
	CPI	2
	JC	GSETSEC	;DON'T SCRAMBLE TRK'S 0-1
	PUSH	H
	LXI	H,SECTBL-1
	MOV	A,C
	ADD	L
	MOV	L,A
	MOV	A,H
	ACI	0
	MOV	H,A
	MOV	A,M
	POP	H
	MOV	C,A
GSETSEC	PUSH	H
	MOV	A,C	;GET PHYSICAL SECTOR
	STA	PHYSEC
VSETSEC	CALL	$-$
	POP	H
	RET
;
SETDMA:
VSETDMA	JMP	$-$
;
READ	MVI	A,1
	STA	WRFLG
	PUSH	H
VREAD	CALL	$-$
	ORA	A
	JZ	READOK
	CALL	ILPRT
	DB	'++READ failed, sector may be invalid++'
	DB	CR,LF,0
READOK	POP	H
	RET
;
WRITE	LDA	WRFLG
	ORA	A
	JNZ	PWRITE
BADW	CALL	ILPRT
	DB	'++CANNOT WRITE UNLESS READ ISSUED'
	DB	CR,LF,0
	JMP	EXPL
PWRITE	PUSH	H
VWRITE	CALL	$-$
	ORA	A
	JZ	WRITEOK
	CALL	ILPRT
	DB	'++WRITE failed++',CR,LF,0
WRITEOK	POP	H
	RET
;
;'SCUSE THIS KLUDGE - IT'S TO SET THE SCRAMBLE
;TABLE TO 1,2,3,4,5.. FOR MY 3600 RPM "FLOPPY"..
;
WARDSK	PUSH	H
	LXI	H,SECTBL
	MVI	B,1
	MVI	C,26
WARDLP	MOV	M,B
	INR	B
	DCR	C
	INX	H
	JNZ	WARDLP
	POP	H
	JMP	PROMPT
;
;HELP
;
HELP	CALL	ILPRT
	DB	'Operands in brackets [...] are optional'
	DB	CR,LF
	DB	CR,LF
	DB	'+[n]	step in [n] sectors;'
	DB	CR,LF
	DB	'-[n]	step out [n] sectors'
	DB	CR,LF
	DB	'=xxx	search for ASCII xxx from curr sector.'
	DB	CR,LF
	DB	'	Caution: upper/lower case matters'
	DB	CR,LF
	DB	'	<nn> for hex: "IN 0" is: =<db><0>'
	DB	CR,LF
	DB	'	"(tab)H,0(CR)(LF)" is: =<9>H,0<D><A>'
	DB	CR,LF
	DB	'<	save current sector'
	DB	CR,LF
	DB	'>	restore saved sector'
	DB	CR,LF
	DB	'?	give help'
	DB	CR,LF
	DB	'A[ff,tt] ASCII dump'
	DB	CR,LF
	DB	'C	Change:'
	DB	CR,LF
	DB	'	CHaddr,byte,byte... (hex)'
	DB	CR,LF
	DB	'  or	CAaddr,data  (Ascii)'
	DB	CR,LF
	DB	'	<xx> Allowed for imbedded hex.'
	DB	CR,LF
	DB	'  or	CHfrom-thru,byte  e.g. ch0-7f,e5'
	DB	CR,LF
	DB	'  or	CAfrom-thru,byte'
	DB	CR,LF
	DB	'D[ff,tt] Dump (hex+ASCII)'
	DB	CR,LF
	DB	'Fn.t	Find file'
	DB	CR,LF
	DB	'Gnn	CP/M Allocation Group nn'
	DB	CR,LF
	DB	'H[ff,tt]	hex dump'
	DB	CR,LF
	DB	'L	Log in drive'
	DB	CR,LF
	DB	'Lx	Log in drive x'
	DB	CR,LF
	DB	'M[nn]	Map [from group nn]'
	DB	CR,LF
	DB	'P	Toggle printer switch'
	DB	CR,LF
	DB	'R	Read current sector'
	DB	CR,LF
	DB	'Snn	Sector nn'
	DB	CR,LF
	DB	'Tnn	Track nn'
	DB	CR,LF
	DB	'V[nn]	View [nn] ASCII sectors'
	DB	CR,LF
	DB	'W	Write current sector'
	DB	CR,LF
	DB	'X	Exit program'
	DB	CR,LF
	DB	'Z[nn]	Sleep [nn tenths]'
	DB	CR,LF
	DB	'/[nn]	Repeat [nn (decimal) times]'
	DB	CR,LF,CR,LF
	DB	'Cancel a function with C or Ctl-C.'
	DB	CR,LF
	DB	'Suspend output with S or Ctl-S.'
	DB	CR,LF
	DB	'Separate commands with ";".'
	DB	CR,LF
	DB	'All "nn" usage except "/" are '
	DB	'HEX.  Use #nn for decimal.'
	DB	CR,LF,0
	JMP	PROMPT
;
;DISK SECTOR ORDER - standard CP/M
;
SECTBL	DB	1,7,13,19,25,5,11,17,23,3,09,15,21
	DB	2,8,14,20,26,6,12,18,24,4,10,16,22
;
BUFAD	DW	100H	;FORCES INITIAL READ
HEXAD	DW	0	;TO RE-FETCH A VALUE
TOGO	DB	0FFH	;REPEAT COUNT (FF=CONT)
TWOUP	DB	0
PFLAG	DB	0	;1=PRINT
GROUP	DB	0
GRPDISP	DB	0
SAVEFLG	DB	0
CURTRK	DB	0
CURSEC	DB	1
PHYSEC	DB	1
TABCOL	DB	0
FILECT	DB	0
DIRPOS	DB	0
FINDFLG	DB	0	;1=MUST POSITION AFTER FIND
FTSW	DB	1	;SEARCH W/O INCREMENT
WRFLG	DB	0	;MAY NOT WRITE UNTIL '+', '-',
;			 OR 'G' COMMAND
	DS	100	;STACK SPACE
STACK:
DUMTYPE	DS	1
SAVEBUF	DS	128
INBUF	DS	128
;
;DIRECTORY READ IN HERE; ALSO SEARCH WORKAREA
;
WORK:
DIRECT	DS	32*64
;
FCB	EQU	5CH
BDOS	EQU	5
RESETDK	EQU	13
SELDK	EQU	14
SRCHF	EQU	17	;SEARCH FIRST
