;LABEL - Utility for setting label for logical volumes
;        on my 8080 computer.
;
;Version 1.0
;08-19-2024
;Jerry Davis
;
   CPU 8080 ;Specify architecture
   PAGE 0   ;Turn off page breaks in listings
;
;
;BIOS Routines
;
wboot   equ   0f403h   ;warm start
const   equ   0f406h   ;console status
conin   equ   0f409h   ;console character in
conout  equ   0f40ch   ;console character out
seldsk  equ   0f41bh   ;select disk
settrk  equ   0f41eh   ;set track number
setsec  equ   0f421h   ;set sector number
setdma  equ   0f424h   ;set dma address
read    equ   0f427h   ;read disk
write   equ   0f42ah   ;write disk
;
;
;BIOS Variables
;
volumes  equ 15         ;number of volumes in the system
;
;
;BDOS Variables
;
tailcnt equ 0080h      ;Length of command line options
tailstr equ 0081h      ;null terminated command line options
;
;
   org 100h
;
;
start:
   lxi d, msg_start    ;point to start message
   call print          ;print it
   lxi h, tailstr      ;parameter pointer
   shld tailptr        ;save it
   lda tailcnt         ;any command line options?
   ora a               ;set flags
   jnz st001           ;Get parameters and set label
stend:
   lxi d, msg_crlf     ;point to new line
   call print          ;print it
   lxi d, msg_usage    ;point to usage heading
   call print          ;print it
   ret                 ;return to CP/M
;
st001:
   call getvolnum      ;get the volume number from parameters
   lda volnum          ;get the volume number parameter
   cpi 0ffh            ;not found?
   jz stend            ;exit if not found
   call getlabel       ;get the volume label
   lhld tailptr        ;get current parater pointer
   mov a, m            ;get label character
   cpi 0               ;no string?
   jz stend            ;exit if not found
   call getvols        ;read in the volume data
   lda volerr          ;check for read error
   cpi 0ffh            ;errored out?
   jnz st002           ;continue of no error
   lxi d, msg_volerr   ;Point to volume read error
   call print          ;print it
   lxi d, msg_crlf     ;Add line space
   call print          ;print it
   jmp 0               ;warm start to CP/M 
st002:
   lda volnum          ;index to volume label to change
   lxi h, labels       ;point to labels list
   lxi b, 16           ;label increment
st003:
   cpi 0               ;done?
   jz st005            ;if so then copy it in label
   dad b               ;move pointer to next label
   dcr a               ;decrement vdrive counter
   jmp st003           ;next label
st005:
   xchg                ;volume label parameter pointer in DE
   lhld tailptr        ;point to volume label from disk
   mvi b, 15           ;max label characters
st006:
   mov a, m            ;get parameter character
   cpi 0               ;end of string?
   jz st007            ;save and go
   stax d              ;put it in volume lable
   inx d               ;point to next character
   inx h               ;point to next character
   dcr b               ;count down
   jz st007            ;save and go if end of string
   jmp st006           ;do again
st007:
   xra a               ;clear A
   stax d              ;put it in volume lable
   call putvols        ;write volume labels to disk
   lda volerr          ;check for read error
   cpi 0ffh            ;errored out?
   jnz stgood          ;continue of no error
   lxi d, msg_volerr   ;point to volume read error
   call print          ;print it
   lxi d, msg_crlf     ;add line space
   call print          ;print it
stexit:
   jmp 0               ;warm start to CP/M 
stgood:
   lxi d, msg_labelok  ;point to label change message
   call print          ;print it
   jmp stexit

;
;
;Get volume number from parameter string
;
getvolnum:
   lhld tailptr        ;point to current option position
getvn01:
   mov a, m            ;get first character
   cpi 0               ;end of parameter string?
   rz                  ;return if end of string
   cpi '0'             ;is it low volume number?
   jc getvn02          ;if not try next param character
   cpi ':'             ;is it greater than 9?
   jc getvn03          ;if not check if second digit exists
getvn02:
   inx h               ;point to next parameter char
   jmp getvn01         ;do again
getvn03:
   sui '0'             ;convert to hex
   mov b, a            ;save first digit in b
   inx h               ;point to next parameter char
   mov a, m            ;get next digit if any
   cpi '0'             ;is it low drive number?
   jc getvn04          ;if not convert first digit and exit
   cpi ':'             ;is it greater than 9?
   jnc getvn04         ;if not convert first digit and exit
   sui '0'             ;convert to hex
   mov c, a            ;save second digit in C
   mov a, b            ;get first digit in A
   cpi 2h              ;greater than one?
   rnc                 ;return if it is
   cpi 0               ;is first digit a zero?
   jz getvn05          ;if it is skip first digit
   mov a, c            ;get second digit in A
   adi 0ah             ;add in decimal 10
   cpi 0fh             ;greater than 14?
   rnc                 ;return if it is
   sta volnum          ;save volume number
   inx h               ;point to next parameter char
   shld tailptr        ;save it
   ret                 
getvn04:
   mov a, b            ;Get first digit in A
   sta volnum          ;save volume number
   inx h               ;point to next parameter char
   shld tailptr        ;save it
   ret
getvn05:
   mov a, c            ;Get second digit in A
   sta volnum          ;save volume number
   inx h               ;point to next parameter char
   shld tailptr        ;save it
   ret
;
;
;Get volume label from parameter string
;
getlabel:
   lhld tailptr        ;get current parameter pointer
getlb01:
   mov a, m            ;get first character
   cpi 0               ;end of parameter string?
   rz                  ;return if end of string
   cpi ' '             ;is it empty space?
   jnz getlbex         ;exit pointing to label string
   inx h               ;next parameter character
   jmp getlb01         ;check next character
getlbex:
   shld tailptr        ;save pointer to label string
   ret                 ;exit
;
;
;Print a null terminated string
;
print:               ;print a message on the console
	ldax d           ;get char pointed to by D into A
	cpi 0            ;end of string?
	jz pend          ;exit if end of string
	mov c, a         ;move char into C for console out
	call conout      ;print it
	inx d            ;point to next character
	jmp print         ;repeat
pend:
	ret              ;and exit
;
;
;Open the volumes file 'volumes.dat' and read in the volume
;labels for each virtual disk.
;Returns 0ffh or non-zero on fail, 0 on success.
;
bopen  equ 15  ;BDOS open function
bclose equ 16  ;BDOS close function
bread  equ 20  ;BDOS sequential read function
bwrite equ 21  ;BDOS sequential write function
bsdma  equ 26  ;BDOS set DMA 
bdos   equ 5   ;BDOS jump address
;
getvols:
   mvi c, bopen            ;bdos open function call
   lxi d, volfcb           ;point to volume FCB
   call bdos               ;open the file
   cpi 0ffh                ;file error?
   jz gverror              ;signal error and exit
   mvi c, bsdma            ;bdos set dma function call
   lxi d, labels           ;point to volumes buffer
   call bdos               ;set dma for volume list
   mvi c, bread            ;bdos read function call
   lxi d, volfcb           ;point to volume fcb
   call bdos               ;read one record
   cpi 0                   ;any errors?
   jnz gverror             ;signal error and exit
   mvi c, bsdma            ;bdos set dma function call
   lxi d, labels+128       ;point to volumes buffer
   call bdos               ;set dma for volume list
   mvi c, bread            ;bdos read function call
   lxi d, volfcb           ;point to volume fcb
   call bdos               ;read one record
   cpi 0                   ;any errors?
   jnz gverror             ;signal error and exit
   mvi c, bclose           ;bdos close function call
   lxi d, volfcb           ;point to volume FCB
   call bdos               ;close the file
   cpi 0                   ;any errors?
   jnz gverror             ;signal error and exit
   ret                     ;done
gverror:
   mvi a, 1                ;signal volume label read error
   sta volerr              ;save it
   ret
;
;
;Open the volumes file 'volumes.dat' and wriute out the volume
;labels for each virtual disk.
;Returns 0ffh or non-zero on fail, 0 on success.
;
putvols:
   mvi a, 0                ;clear FCB variables
   sta fcbextn             ;clear extent
   sta fcbsrec             ;clear sequential record number
   mvi c, bopen            ;bdos open function call
   lxi d, volfcb           ;point to volume FCB
   call bdos               ;open the file
   cpi 0ffh                ;file error?
   jz pverror              ;signal error and exit
   mvi c, bsdma            ;bdos set dma function call
   lxi d, labels           ;point to volumes buffer
   call bdos               ;set dma for volume list
   mvi c, bwrite           ;bdos write function call
   lxi d, volfcb           ;point to volume fcb
   call bdos               ;read one record
   cpi 0                   ;any errors?
   jnz gverror             ;signal error and exit
   mvi c, bsdma            ;bdos set dma function call
   lxi d, labels+128       ;point to volumes buffer
   call bdos               ;set dma for volume list
   mvi c, bwrite           ;bdos write function call
   lxi d, volfcb           ;point to volume fcb
   call bdos               ;read one record
   cpi 0                   ;any errors?
   jnz pverror             ;signal error and exit
   mvi c, bclose           ;bdos close function call
   lxi d, volfcb           ;point to volume FCB
   call bdos               ;close the file
   cpi 0                   ;any errors?
   jnz pverror             ;signal error and exit
   ret                     ;done
pverror:
   mvi a, 1                ;signal volume label read error
   sta volerr              ;save it
   ret
;
;
msg_start:
   dw 0d0ah
   db 'LABEL v1.0 - Label virtual disks'
   dw 0d0ah
   db 0
;
;
msg_volerr:
   db '*** Error reading volume labels!'
   dw 0d0ah
   db 0
;
;
msg_labelok:
   db 'Volume label changed'
   dw 0d0ah
   db 0
;
;
msg_usage:
   db 'USAGE: LABEL <volume number> <volume label>'
   dw 0d0ah
   dw 0d0ah
   db 'volume number = 0..14'
   dw 0d0ah
   db 0
;
;
msg_crlf:
   dw 0d0ah
   db 0
;
volnum  db 0ffh              ;volume number
count   db 0                 ;volumes to display
tailptr dw 0                 ;pointer to parameters list
;
volerr: db 0                 ;volume error flag
;
volfcb:
fcbdisk: db 1                ;always use drive A
fcbname: db 'VOLUMES', 20h   ;volume labels file name
fcbtype: db 'DAT'            ;volume labels file type
fcbextn: db 0                ;volume labels extent
fcbresv: db 0,0              ;reserved
fcbrecs: db 0                ;volume labels records used
fcbaloc: dw 0,0,0,0,0,0,0,0  ;allocation blocks
fcbsrec: db 0                ;sequential record number
fcbrrec: dw 0                ;random record number
fcbreco: db 0                ;random record overflow
;
labels ds 256                ;storage for volume labels
;
   end