10 REM ----------------------------------------------
   20 REM CLONE : Disk Copier
   30 REM ----------------------------------------------
   40 DIM param 12, sectab 39, data 256*10-1
   50 osword=&FFF1
   60 MODE 7
   70 PROCbegin               :REM get source drive and dest drive
   80 PROChowmany             :REM how many tracks on source
   90 PROCinsert              :REM get user ready
  100 
  110 FOR T%=0 TO maxtrack%
  120     REM seek track 0 on source
  130     PROCseek0(sdrive%)
  140   
  150     REM read sectors IDs from source
  160     PROCsectorids(T%)
  170   
  180     REM if sectors found, clone them
  190     IF param?10 = 0:PROCclone
  200 NEXT
  210 PRINT TAB(0,22);CHR$133;"      cloning complete      "
  220 END
  230 
  240 DEFPROCclone
  250 REM establish lowest sector num
  260 PROClowest
  270 
  280 REM set source track register to logical
  290 PROCtrack(sdrive%, ?sectab)
  300 
  310 REM read the data for this track
  320 PROCread(?sectab)
  330 
  340 REM if drives are the same, swap
  350 IF sdrive%=ddrive%:PROCswapo
  360 
  370 REM seek track 0 on dest
  380 PROCseek0(ddrive%)
  390 
  400 REM copy source format to dest format
  410 PROCformat(T%)
  420 
  430 REM set dest track register to logical
  440 PROCtrack(ddrive%,?sectab)
  450 
  460 REM copt source data to dest data
  470 PROCwrite(?sectab)
  480 
  490 REM if drives are the same, swap
  500 IF sdrive%=ddrive%:PROCswapi
  510 ENDPROC
  520 
  530 DEFPROCbegin
  540 REM find out source and destination drives
  550 PROChead
  560 REPEAT
  570     PRINT TAB(0,5);STRING$(38," ")
  580     PRINT TAB(0,5);CHR$134;"enter source drive (0-3) >";
  590     INPUT " " sdrive%
  600 UNTIL sdrive%>-1 AND sdrive%<4
  610 REPEAT
  620     PRINT TAB(0,7);STRING$(38," ")
  630     PRINT TAB(0,7);CHR$134;"enter destination drive (0-3) >";
  640     INPUT " " ddrive%
  650 UNTIL ddrive%>-1 AND ddrive%<4
  660 ENDPROC
  670 
  680 DEFPROCdisplay
  690 REM display the track being processed
  700 PROChead
  710 PRINT TAB(0,5);CHR$134;" drive";CHR$130;sdrive%
  720 PRINT CHR$134;" physcial track ";CHR$130;T%
  730 IF param?10<>0:ENDPROC
  740 PRINT TAB(00,8);CHR$134;"phys"
  750 PRINT TAB(00,9);CHR$134;"sect"
  760 PRINT TAB(06,8);CHR$134;"log "
  770 PRINT TAB(06,9);CHR$134;"trck"
  780 PRINT TAB(12,8);CHR$134;"head"
  790 PRINT TAB(18,8);CHR$134;"log "
  800 PRINT TAB(18,9);CHR$134;"sect"
  810 PRINT TAB(24,8);CHR$134;"size"
  820 @%=3
  830 FOR I%=0 TO 9
  840     J%=I%+10
  850     PRINT TAB(02,J%);CHR$130;I%
  860     PRINT TAB(08,J%);sectab?(4*I%+0)
  870     PRINT TAB(14,J%);sectab?(4*I%+1)
  880     PRINT TAB(20,J%);sectab?(4*I%+2)
  890     PRINT TAB(26,J%);sectab?(4*I%+3)
  900 NEXT
  910 ENDPROC
  920 
  930 DEFPROCformat(track%)
  940 REM format dest disk to match source
  950 param?0  = ddrive%      :REM dest drive number
  960 param!1  = sectab       :REM sector table
  970 param?5  = &05          :REM number of parameters
  980 param?6  = &63          :REM format command code
  990 param?7  = track%       :REM physical track number
 1000 param?8  = 21           :REM gap3 size
 1010 param?9  = &2A          :REM sector size/number of sectors
 1020 param?10 = 0            :REM gap5 size
 1030 param?11 = 16           :REM gap1 size
 1040 A%=&7F
 1050 X%=param
 1060 Y%=X% DIV 256
 1070 CALL osword
 1080 IF param?12=0:ENDPROC
 1090 PRINT TAB(4,22);CHR$133;"format: bad result = &";~param?12:END
 1100 ENDPROC
 1110 
 1120 DEFPROChead
 1130 REM screen header
 1140 CLS
 1150 PRINT TAB(8,2);CHR$141;CHR$131;"DISK CLONER"
 1160 PRINT TAB(8,3);CHR$141;CHR$131;"DISK CLONER"
 1170 ENDPROC
 1180 
 1190 DEFPROChowmany
 1200 REM find out how many tracks on source
 1210 REM *DRIVE sdrive%
 1220 OSCLI "DRIVE "+STR$sdrive%
 1230 REM get number of sectors
 1240 A%=&7E
 1250 X%=param
 1260 Y%=X% DIV 256
 1270 CALL osword
 1280 maxtrack%=(!param DIV 2560)-1
 1290 ENDPROC
 1300 
 1310 DEFPROCinsert
 1320 REM get disks in drive amd wait for user
 1330 IF sdrive%=ddrive%:PROCswapi:ENDPROC
 1340 PROChead
 1350 PRINT TAB(0,5);CHR$134;"insert source disk in drive ";sdrive%
 1360 PRINT TAB(0,6);CHR$134;"insert destination disk in drive ";ddrive%
 1370 PRINT TAB(3,8);CHR$133;"press SPACE when ready to go"
 1380 REPEAT
 1390 UNTIL INKEY(100)=32
 1400 PROChead
 1410 ENDPROC
 1420 
 1430 DEFPROClowest
 1440 REM find out lowest logical sector
 1450 lowsec%=sectab?2
 1460 FOR I%=1 TO 9
 1470     IF sectab?(4*I%+2) < lowsec%:lowsec%=sectab?(4*I%+2)
 1480 NEXT
 1490 ENDPROC
 1500 
 1510 DEFPROCread(track%)
 1520 REM read a track from source
 1530 param?0  = sdrive%      :REM source drive number
 1540 param!1  = data         :REM data buffer
 1550 param?5  = &03          :REM number of parameters
 1560 param?6  = &57          :REM read code
 1570 param?7  = track%       :REM logical track number
 1580 param?8  = lowsec%      :REM logical sector
 1590 param?9  = &2A          :REM sector size/number of sectors
 1600 A%=&7F
 1610 X%=param
 1620 Y%=X% DIV 256
 1630 CALL osword
 1640 del%=param?10 AND &20   :REM get delete bit
 1650 res%=param?10 AND &1E   :REM mask off delete bit
 1660 del$="ordinary data marks"
 1670 IF del%<>0:del$="delete data marks"
 1680 PRINT TAB(4,21);CHR$130;del$
 1690 IF res%=0:ENDPROC
 1700 PRINT TAB(4,22);CHR$133;"read: bad result = &";~param?10:END
 1710 ENDPROC
 1720 
 1730 DEFPROCsectorids(track%)
 1740 REM read sector IDs from source track
 1750 param?0  = sdrive%      :REM source drive number
 1760 param!1  = sectab       :REM sector table
 1770 param?5  = &03          :REM number of parameters
 1780 param?6  = &5B          :REM read sector IDs code
 1790 param?7  = track%       :REM logical track number
 1800 param?8  = 0
 1810 param?9  = 10           :REM number of sectors
 1820 A%=&7F
 1830 X%=param
 1840 Y%=X% DIV 256
 1850 CALL osword
 1860 PROCdisplay
 1870 IF param?10=0:ENDPROC
 1880 PRINT TAB(2,44);CHR$133;"ids: bad result = &";~param?10
 1890 ENDPROC
 1900 
 1910 DEFPROCseek0(drive%)
 1920 REM seek to track 0
 1930 param?0  = drive%       :REM drive
 1940 param!1  = -1           :REM no address
 1950 param?5  = 1            :REM number of parameters
 1960 param?6  = &69          :REM seek command code
 1970 param?7  = 0            :REM track 0
 1980 A%=&7F
 1990 X%=param
 2000 Y%=X% DIV 256
 2010 CALL osword
 2020 IF param?8=0:ENDPROC
 2030 PRINT TAB(2,44);CHR$133;"seek0: bad result = &";~param?8
 2040 ENDPROC
 2050 
 2060 DEFPROCswapi
 2070 REM swap back to source disk
 2080 PROChead
 2090 PRINT TAB(0,5);CHR$134;"insert source disk in drive ";sdrive%
 2100 PRINT TAB(0,8);CHR$134;"press SPACE when ready to go"
 2110 REPEAT
 2120 UNTIL INKEY(100)=32
 2130 PROChead
 2140 ENDPROC
 2150 
 2160 DEFPROCswapo
 2170 REM swap back to destination disk
 2180 PROChead
 2190 PRINT TAB(0,5);CHR$134;"insert destination disk in drive ";ddrive%
 2200 PRINT TAB(0,8);CHR$134;"press SPACE when ready to go"
 2210 REPEAT
 2220 UNTIL INKEY(100)=32
 2230 PROChead
 2240 ENDPROC
 2250 
 2260 DEFPROCtrack(drive%,to%)
 2270 REM alter track register
 2280 param?0  = &FF          :REM use current drive
 2290 param!1  = -1           :REM no address
 2300 param?5  = 2            :REM number of parameters
 2310 param?6  = &7A          :REM write track reg code
 2320 REM pick the correct track register
 2330 REM for drive 0/2, register = &12
 2340 REM for drive 1/3, register = &1A
 2350 param?7  = &12+8*(drive% MOD 2)
 2360 param?8  = to%          :REM new track number
 2370 A%=&7F
 2380 X%=param
 2390 Y%=X% DIV 256
 2400 CALL osword
 2410 IF param?9=0:ENDPROC
 2420 PRINT TAB(2,44);CHR$133;"track: bad result = &";~param?9:END
 2430 ENDPROC
 2440 
 2450 DEFPROCwrite(track%)
 2460 REM copy data from source track to dest track
 2470 param?0  = ddrive%      :REM dest drive number
 2480 param!1  = data         :REM data buffer
 2490 param?5  = &03          :REM number of parameters
 2500 REM pick correct write code
 2510 REM if not deleted data, use &4B
 2520 REM if deleted data, use &4F
 2530 param?6  = &4B          :REM write code
 2540 IF del%<>0:param?6=&4F
 2550 param?7  = track%       :REM logical track number
 2560 param?8  = lowsec%      :REM logical sector
 2570 param?9  = &2A          :REM sector size/number of sectors
 2580 A%=&7F
 2590 X%=param
 2600 Y%=X% DIV 256
 2610 CALL osword
 2620 res%=param?10 AND &1E:REM mask off delete bit
 2630 IF res%=0:ENDPROC
 2640 PRINT TAB(4,22);CHR$133;"write: bad result = &";~param?10:END
 2650 ENDPROC