;
;****************************************************
;*                                                  *
;*    Sample Random Access Program for MP/M-86      *
;*                                                  *
;****************************************************
;
;    BDOS Functions
;
coninp  equ     1       ;console input function
conout  equ     2       ;console output function
pstring equ     9       ;print string until '$'
rstring equ     10      ;read console buffer
version equ     12      ;return version number
openf   equ     15      ;file open function
closef  equ     16      ;close function
makef   equ     22      ;make file function
readr   equ     33      ;read random
writer  equ     34      ;write random
writerz equ     40      ;write random zero fill
;
;   Equates for non graphic characters
cr      equ     0dh     ;carriage return
lf      equ     0ah     ;line feed
;
;
;  load SP, ready file for random access    
;
	cseg
	pushf			;push flags in CCP stack
	pop	ax		;save flags in AX
	cli			;disable interrupts
	mov	bx,ds		;set SS register to base of DATA group
	mov	ss,bx		;set SS, SP with interrupts disabled 
	mov	sp,offset stack	;    for 80888
	push	ax		;restore the flags
	popf
;
;	CP/M-86 initial release returns the file
;	system version number of 2.2:  check is
;	shown below for illustration purposes.
;
	mov	cl,version
        call    bdos
	cmp	al,20h		;version 2.0 or later?
        jnb     versok
	;       bad version, message and go back
	mov	dx,offset badver
        call    print
        jmp     abort
;
versok:
;       correct version for random access
	mov	cl,openf	;open default fct
	mov	dx,offset fcb
        call    bdos
        inc     al       	;err 255 becomes zero
        jnz     ready
;
;       cannot open file, so create it
	mov	cl,makef
	mov	dx,offset fcb
        call    bdos
        inc     al       	;err 255 becomes zero
        jnz     ready
;
;       cannot create file, directory full
	mov	dx,offset nospace
        call    print
	jmp	abort		;back to ccp
;
;   loop back to "ready" after each command         
;
ready:
;       file is ready for processing
;
	call	readcom		;read next command
	mov	ranrec,dx	;store input record#
	mov	ranovf,ch	;set high byte 
	cmp	al,'Q'		;quit?
        jnz     notq
;
;       quit processing, close file
	mov	cl,closef
	mov	dx,offset fcb
        call    bdos
	inc	al	;err 255 becomes 0
	jnz	$+5
        jmp     error   ;error message, retry
	jmp 	abort	;back to ccp
;
;
;  end of quit command, process write   
;
;
notq:
;       not the quit command, random write?
	cmp	al,'W'
        jnz     notw
;
;       this is a random write, fill buffer until cr
	mov	dx,offset datmsg
	call	print		;data prompt
	mov	cx,127		;up to 127 characters
	mov	bx,offset buff	;destination
rloop:  ;read next character to buff
	push	cx		;save loop conntrol
	push	bx		;next destination
        call    getchr  	;character to AL
	pop	bx		;restore destination
	pop	cx		;restore counter
	cmp	al,cr		;end of line?
        jz      erloop
;       not end, store character
	mov	byte ptr [bx],al
	inc	bx		;next to fill
	loop	rloop		;decrement cx ..loop if not 0
erloop:
;       end of read loop, store 00
	mov	byte ptr [bx],0h
;
;       write the record to selected record number
	mov	cl,writer
	mov	dx,offset fcb
        call    bdos
	or	al,al		;error code zero?
	jz	ready	;for another record
        jmps     error   ;message if not
;
;
;
;  end of write random command, process write random zero fill
;
;
notw:
;       not the quit command, random write?
	cmp	al,'Z'
        jnz     notz
;
;       this is a random write, fill buffer until cr
	mov	dx,offset datmsg
	call	print		;data prompt
	mov	cx,127		;up to 127 characters
	mov	bx,offset buff	;destination
rzloop: ;read next character to buff
	push	cx		;save loop conntrol
	push	bx		;next destination
        call    getchr  	;character to AL
	pop	bx		;restore destination
	pop	cx		;restore counter
	cmp	al,cr		;end of line?
        jz      erzloop
;       not end, store character
	mov	byte ptr [bx],al
	inc	bx		;next to fill
	loop	rzloop		;decrement cx ..loop if not 0
erzloop:
;       end of read loop, store 00
	mov	byte ptr [bx],0h
;
;       write the record to selected record number
	mov	cl,writerz
	mov	dx,offset fcb
        call    bdos
	or	al,al		;error code zero?
	jnz	$+5
	jmp	ready	;for another record
        jmps     error   ;message if not
;
;
;
;  end of write random zero fill command, process read
;
;
notz:
;       not a write command, read record?
	cmp	al,'R'
	jz	ranread
        jmps     error   ;skip if not
;
;       read random record
ranread:
	mov	cl,readr
	mov	dx,offset fcb
        call    bdos
	or	al,al		;return code 00?
	jz	readok
        jmps     error
;
;       read was successful, write to console
readok:
	call	crlf		;new line
	mov	cx,128		;max 128 characters
	mov	si,offset buff	;next to get
wloop:
	lods	al		;next character
	and	al,07fh		;mask parity
	jnz	wloop1
	jmp	ready		;for another command if 00
wloop1:
	push	cx		;save counter
	push	si		;save next to get
	cmp	al,' '		;graphic?
	jb	skipw		;skip output if not graphic
	call	putchr		;output character
skipw:
	pop	si
	pop	cx
	loop	wloop		;decrement CX and check for 00
        jmp     ready
;
;
;  end of read command, all errors end-up here     
;
;
error:
	mov	dx,offset errmsg
        call    print
        jmp     ready
;
;  BDOS entry subroutine
bdos:
	int	224		;entry to BDOS if by INT 224
	ret
;
abort:				;return to CCP
	mov	cl,0
	call 	bdos		;use function 0 to end execution
;
;  utility subroutines for console i/o       
;
getchr:
        ;read next console character to a
	mov	cl,coninp
        call    bdos
        ret
;
putchr:
        ;write character from a to console
	mov	cl,conout
	mov	dl,al		;character to send
        call    bdos    	;send character
        ret
;
crlf:
        ;send carriage return line feed
	mov	al,cr		;carriage return
        call    putchr
	mov	al,lf		;line feed
        call    putchr
        ret
;
print:
        ;print the buffer addressed by dx until $
        push    dx
        call    crlf
	pop	dx		;new line
	mov	cl,pstring
        call    bdos    	;print the string
        ret
;
readcom:
        ;read the next command line to the conbuf
	mov	dx,offset prompt
	call	print		;command?
	mov	cl,rstring
	mov	dx,offset conbuf
        call    bdos    	;read command line
;       command line is present, scan it
	mov	ax,0		;start with 0000
	mov	bx,offset conlin
	mov     ch,0            ;zero high byte of 3 byte result
readc:	mov	dl,[bx]		;next command character
	inc	bx		;to next command position
	mov	dh,0		;zero high byte for add
	or	dl,dl		;check for end of command
	jnz	getnum
	ret
;       not zero, numeric?
getnum:
	sub	dl,'0'
	cmp	dl,10		;carry if numeric
	jnb	endrd
	cmp	ch,0
	jnz	error		;error - number too large
	push	dx		;multiply by 10
	mov	cx,10
	mul	cx
	mov	ch,dl
	pop	dx
	add	ax,dx		;+digit
	adc	ch,0
	jmps    readc   	;for another char
endrd:
;       end of read, restore value in a and return value in bx
	mov	dx,ax		;return value  in DX
	mov	al,-1[bx]
	cmp	al,'a'		;check for lower case
	jnb	transl
	ret
transl:	and	al,5fH	;translate to upper case
        ret
;
;
; Template for Page 0 of Data Group
;   Contains default FCB and DMA buffer
;
	dseg
	org	05ch
fcb	rb	33 		;default file control block
ranrec	rw	1		;random record position
ranovf	rb	1		;high order (overflow) byte
buff	rb	128		;default DMA buffer
;
;  string data area for console messages           
badver        db      'sorry, you need cp/m version 2$'
nospace       db      'no directory space$'
datmsg        db      'type data: $'
errmsg        db      'error, try again.$'
prompt        db      'next command? $'
;
;
;    fixed and variable data area
;
conbuf db      conlen  ;length of console buffer
consiz rs      1       ;resulting size after read
conlin rs      32      ;length 32 buffer
conlen equ     offset $ - offset consiz
;
        rs      31      ;16 level stack
stack	rb	1
	db	0	;end byte for GENCMD
        end
