10 REM > FREE/SRC
   20 REM Z80 Source code for FREE.COM
   30 REM v0.01 28-Nov-88 JGH: Initial version
   40 :
   50 DIM mcode% &800:start%=&100:BDOS=5
   60 :
   70 FOR P=0 TO 1
   80   O%=mcode%:P%=start%
   90   [OPT P*3+4
  100   LD C,25:CALL BDOS:PUSH AF     :\ Read current drive
  110   LD A,(&5C):AND A:JR Z,NoDrive :\ No drive parameter
  120   DEC A:LD E,A:LD C,14:CALL BDOS:\ Select drive
  130   .NoDrive
  140   :
  150   LD C,27:CALL BDOS:PUSH HL     :\ Get allocation table address
  160   LD C,31:CALL BDOS             :\ Get disk parameter block address
  170   INC HL:INC HL:LD A,(HL)       :\ A=BlockShift
  180   INC HL:INC HL:INC HL          :\ HL=>DiskSizeMax
  190   LD E,(HL):INC HL:LD D,(HL)    :\ DE=DiskSizeMax
  200   :
  210   POP IX:PUSH DE:PUSH AF:LD HL,0:\ Save size, zero total
  220   \ IX=> alloc, B=8 loop, C=byte, DE=DSM, HL=used count
  230   :
  240   .Loop0
  250   LD B,8:LD C,(IX+0)            :\ Set up inner loop, get byte
  260   .Loop1
  270   SLA C:JR NC,BitZero:INC HL    :\ Inc total if bit set
  280   .BitZero
  290   DEC DE:LD A,D:OR E:JR Z,TotalCounted
  300   DJNZ Loop1:INC IX:JR Loop0    :\ Fetch another Alloc byte
  310   :
  320   .TotalCounted
  330   POP AF:POP DE                 :\ A=BSH, DE=DSM
  340   EX DE,HL:AND A:SBC HL,DE      :\ DE=used, HL=free
  350   DEC A
  360   .Loop3
  370   SLA E:RL D:SLA L:RL H         :\ Shift DE and HL left
  380   DEC A:JR NZ,Loop3
  390   :
  400   PUSH DE:CALL PrNumbers
  410   LD DE,StrFree:CALL PrString
  420   POP HL:CALL PrNumbers
  430   LD DE,StrUsed:CALL PrString
  440   :
  450   POP AF:LD E,A:LD C,14:JP BDOS :\ Restore drive
  460   :
  470   .PrNumbers
  480   LD (Total+1),HL:SLA L:RL H    :\ Store, convert to 128-byte sector count
  490   LD A,H:CALL PrHex:LD A,L:CALL PrHex:\  Print sector total
  500   LD DE,StrSectors:CALL PrString
  510   LD A,ASC" ":LD (Lead),A
  520   LD C,&F:LD DE,&4240:CALL PrDec
  530   :
  540   CALL PrComma
  550   LD C,&1:LD DE,&86A0:CALL PrDec
  560   LD DE,10000:CALL PrDec0
  570   LD DE,1000:CALL PrDec0
  580   :
  590   CALL PrComma
  600   LD DE,100:CALL PrDec0
  610   LD DE,10:CALL PrDec0
  620   LD A,(Total):CALL PrNybble
  630   LD DE,StrBytes
  640   :
  650   .PrString
  660   LD C,9:JP BDOS
  670   :
  680   .PrHex
  690   PUSH AF:RRA:RRA:RRA:RRA
  700   CALL PrNybble:POP AF
  710   :
  720   .PrNybble
  730   AND 15:CP 10
  740   JR C,P%+4:ADD A,7
  750   ADD A,ASC"0"
  760   .OUTCHR
  770   PUSH HL
  780   LD E,A:LD C,2:CALL BDOS
  790   POP HL:RET
  800   :
  810   .PrDec0
  820   LD C,0
  830   .PrDec
  840   LD B,&FF
  850   LD A,(Total+2):LD HL,(Total)
  860   .DecLoop
  870   INC B:AND A:SBC HL,DE:SBC A,C
  880   JR NC,DecLoop
  890   ADD HL,DE:ADC A,C
  900   LD (Total+2),A:LD (Total),HL
  910   LD A,B:AND A:JR Z,PrZero
  920   LD A,ASC"0":LD (Lead),A
  930   LD A,B:JP PrNybble
  940   .PrZero
  950   LD A,(Lead):JP OUTCHR
  960   :
  970   .PrComma
  980   LD A,(Lead):CP ASC" ":JR Z,OUTCHR
  990   LD A,ASC",":JP OUTCHR
 1000   :
 1010   RET
 1020   :
 1030   .Lead
 1040   DEF" "
 1050   :
 1060   .Total
 1070   DEFB 0:DEFW 0
 1080   :
 1090   .StrSectors
 1100   DEF" Sectors = $"
 1110   :
 1120   .StrBytes
 1130   DEF" Bytes $"
 1140   .StrFree
 1150   DEF"Free":DEFB 13:DEFB 10:DEF"$"
 1160   .StrUsed
 1170   DEF"Used":DEFB 13:DEFB 10:DEF"$"
 1180   :
 1190 ]NEXT
 1200 A$="*SAVE FREE.COM "+STR$~mcode%+" "+STR$~O%
 1210 PRINT A$