10 REM ----------------------------------------------
   20 REM EDIT - Disk editor
   30 REM ----------------------------------------------
   40 
   50 DIM param 12, sectab 39, data 255
   60 osword=&FFF1
   70 MODE 7
   80 PROCbegin        :REM get drive
   90 REPEAT           :REM repeat
  100     PROCmain       :REM main loop
  110     MODE 7         :REM normal cursor
  120 UNTIL get%=&8F   :REM until user finished
  130 END
  140 
  150 
  160 DEFPROCbegin
  170 VDU 23;11,0;0;0;0;
  180 REM set KEY 0 to &8C, KEY 1 to &8D
  190 REM set KEY 2 to &8E, KEY 3 to &8F
  200 *KEY0 |!|L
  210 *KEY1 |!|M
  220 *KEY2 |!|N
  230 *KEY3 |!|O
  240 REM display header
  250 PROChead
  260 REM get drive number
  270 REPEAT
  280     PRINTTAB(3,5);STRING$(38," ")
  290     PRINTTAB(3,5);CHR$130;"Enter drive (0-3)";
  300     INPUT " > "drive%
  310 UNTIL drive%>-1 AND drive%<4
  320 REM *DRIVE for this drive number
  330 OSCLI "DRIVE "+STR$drive%
  340 REM get user to insert disk
  350 PRINTTAB(3,7);CHR$130;"insert disk in drive ";drive%
  360 PRINTTAB(3,8);CHR$130;"press SPACE when ready to go"
  370 REPEAT UNTIL INKEY(100)=32
  380 REM find out how many tracks
  390 A%=&7E
  400 X%=param
  410 Y%=X% DIV 256
  420 CALL osword
  430 maxtrack%=(!param DIV 2560)-1
  440 ENDPROC
  450 
  460 DEFPROCchoices
  470 REM disable cursor editing
  480 *FX4,1
  490 REM display choices
  500 PRINTTAB(0,21);CHR$133;"you may edit the";
  510 PRINTCHR$131;"hex";CHR$133;"or the";CHR$129;"ASCII"
  520 PRINTTAB(0,22);CHR$131;"(f0 = other half  : f1 = main menu   )"
  530 PRINTTAB(0,23);CHR$131;"(f2 = update disk : f3 = quit program)"
  540 ENDPROC
  550 
  560 
  570 
  580 DEFPROCcoord
  590 REM get cursor coordinates
  600 x%=POS
  610 y%=VPOS
  620 ENDPROC
  630 
  640 DEFPROCdispdata
  650 REM display header
  660 PROChead
  670 REM display a 16 by 8 matrix of data
  680 FOR I%=1 TO 16
  690     PROCdispline(I%)
  700 NEXTI%
  710 REM display choices
  720 PROCchoices
  730 REM position cursor at 1st byte
  740 VDU 31,5,4
  750 ENDPROC
  760 
  770 DEFPROCdispline(W%)
  780 REM display a line of data
  790 REM set J%=relative byte number
  800 J%=part%*128 + 8*(W%-1)
  810 REM set start% to address of 1st byte of data
  820 start%=data+J%
  830 REM set str$ to 2-byte hex string of J%
  840 PROCstring(J%)
  850 REM print it in green and set up the rest in yellow
  860 PRINT TAB(0,W%+3);CHR$130;str$;CHR$131;" ";
  870 REM initialise ASCII representaion of data
  880 A$=""
  890 REM for each of 8 bytes of data
  900 FOR Z%=0 TO 7
  910     REM set C% = next byte
  920     C%=start%?Z%
  930     REM store ASCII representation in A$
  940     IF C%<32 OR C%>126:A$=A$+"." ELSE A$=A$+CHR$(C%)
  950     REM set str$ = 2-byte hex string of C%
  960     PROCstring(C%)
  970     REM print it
  980     PRINTstr$;" ";
  990 NEXT
 1000 REM print ACSII representation in red
 1010 PRINT CHR$129;A$
 1020 ENDPROC
 1030 
 1040 DEFPROCdown
 1050 REM move cursor down one line
 1060 VDU 10
 1070 REM get cursor coordinates
 1080 PROCcoord
 1090 REM if it's fallen off the bottom, wrap around to top
 1100 IF y%>19 THEN VDU 31,x%,4
 1110 ENDPROC
 1120 
 1130 DEFPROCedit
 1140 REM get cursor coordinates
 1150 PROCcoord
 1160 REM if user editing ASCII do edit2
 1170 IF x%>29:PROCedit2:ENDPROC
 1180 REM user is editing hex, so change key-in from ASCII to hex
 1190 get%=get%-&30
 1200 IF get%>9:get%=get%-7
 1210 REM make sure the key-in is valid
 1220 IF get%<0 :ENDPROC
 1230 IF get%>15:ENDPROC
 1240 REM calculate relative memory address of byte being edited
 1250 mem%=part%*128 + 8*(y%-4) + (x%-5) DIV 3
 1260 REM find existing value of left nibble
 1270 left%=data?mem% DIV 16
 1280 REM find existing value of right nibble
 1290 right%=data?mem% MOD 16
 1300 REM if user is editing left nibble, overwrite left nibble
 1310 REM else overwrite right nibble
 1320 IF (x%-5) MOD 3=0:left%=get% ELSE right%=get%
 1330 REM put new value back in memory
 1340 data?mem%=16*left%+right%
 1350 REM redisplay whole line
 1360 PROCdispline(y%-3)
 1370 REM restore cursor position
 1380 VDU 31,x%,y%
 1390 REM move cursor right
 1400 PROCright
 1410 ENDPROC
 1420 
 1430 DEFPROCedit2
 1440 REM get relative address of byte being edited
 1450 mem%=part%*128 + 8*(y%-4) + x%-30
 1460 REM overwrite this byte with key-in value
 1470 data?mem%=get%
 1480 REM redisplay whole line
 1490 PROCdispline(y%-3)
 1500 REM restore cursor position
 1510 VDU 31,x%,y%
 1520 REM move cursor right
 1530 PROCright
 1540 ENDPROC
 1550 
 1560 DEFPROCerr
 1570 REM handle a bad result from OSWORD
 1580 PROChead
 1590 PRINTTAB(0,5);CHR$129;bad$
 1600 PRINTTAB(0,6);CHR$129;"result = &";STR$~res%
 1610 PRINTTAB(0,8);CHR$133;"press SPACE for main menu"
 1620 REPEAT UNTIL INKEY(100)=32
 1630 ENDPROC
 1640 
 1650 DEFPROCget
 1660 REM get keyboard input
 1670 REPEAT
 1680     get%=GET
 1690     REM if user pressed f0, toggle next half of sector display
 1700     IF get%=&8C:part%=part% EOR 1:PROCdispdata
 1710     REM if user pressed f2, update the disk
 1720     IF get%=&8E:PROCwrite
 1730     REM if cursor key, move cursor
 1740     IF get%=&88:PROCleft
 1750     IF get%=&89:PROCright
 1760     IF get%=&8A:PROCdown
 1770     IF get%=&8B:PROCup
 1780     REM if editing a byte, do edit
 1790     IF get%>&1F AND get%<&80:PROCedit
 1800     REM repeat all this until user wants to
 1810     REM return to main menu, updater disk or quit
 1820 UNTIL get%>&8C
 1830 ENDPROC
 1840 
 1850 DEFPROChead
 1860 REM display screen header
 1870 CLS
 1880 PRINTTAB(10,0);CHR$141;CHR$132;"DISK EDITOR"
 1890 PRINTTAB(10,1);CHR$141;CHR$132;"DISK EDITOR"
 1900 ENDPROC
 1910 
 1920 DEFPROCleft
 1930 REM move cursor left
 1940 VDU 8
 1950 REM get cursor corrdinates
 1960 PROCcoord
 1970 REM if it's falled off at the left, wrap around to the right
 1980 IF x%<5 :VDU 31,37,y%:ENDPROC
 1990 REM if it's at X=28 or X=29, move it to X=30
 2000 IF x%>29:ENDPROC
 2010 IF x%=28:VDU 8:ENDPROC
 2020 IF x%=29:VDU 8,8:ENDPROC
 2030 REM if it's in a gap, move it left
 2040 IF (x%-4) MOD 3=0:VDU 8
 2050 ENDPROC
 2060 
 2070 DEFPROCmain
 2080 VDU 23;11,0;0;0;0;
 2090 REM main menu program loop
 2100 REM find out which track
 2110 PROCmenu
 2120 REM seek track 0, reset track register
 2130 PROCseek(0)
 2140 REM read sector IDs from wanted track
 2150 PROCsectorids
 2160 REM if any problems, return to main
 2170 IF res%<>0:ENDPROC
 2180 REM find out which sector
 2190 PROCwhichsec
 2200 REM set track register
 2210 PROCtrack(?sectab)
 2220 REM read the sector
 2230 PROCread
 2240 REM if any problems, return to main
 2250 IF res%<>0:ENDPROC
 2260 REM initialise display to 1st 128 bytes of sector
 2270 part%=0
 2280 REM special editing cursor
 2290 VDU 23;10,0;0;0;0;
 2300 VDU 23;11,255;0;0;0;
 2310 REM display 128 bytes of data
 2320 PROCdispdata
 2330 REM start reading from keyboard
 2340 PROCget
 2350 ENDPROC
 2360 
 2370 DEFPROCmenu
 2380 REM find out which track
 2390 @%=2
 2400 PROChead
 2410 REPEAT
 2420     PRINTTAB(0,5);STRING$(38," ")
 2430     PRINTTAB(0,5);CHR$130;"Enter track number (0 - ";maxtrack%;")";
 2440     INPUT " > "track%
 2450 UNTIL track%>-1 AND track%<maxtrack%+1
 2460 ENDPROC
 2470 
 2480 DEFPROCow(R%)
 2490 REM call OSWORD and set res% to result register
 2500 REM on entry, R%=index into param block for result register
 2510 A%=&7F
 2520 X%=param
 2530 Y%=X% DIV 256
 2540 CALL osword
 2550 res%=param?R%
 2560 ENDPROC
 2570 
 2580 DEFPROCread
 2590 REM read a sector
 2600 param?0=drive%    :REM drive
 2610 param!1=data      :REM address
 2620 param?5=3         :REM num of parameters
 2630 param?6=&57       :REM read
 2640 param?7=?sectab   :REM track
 2650 param?8=sector%   :REM sector
 2660 param?9=&21       :REM one sector
 2670 PROCow(10)
 2680 REM save delete bit from result register
 2690 del%=res% AND &20
 2700 REM mask off the deleted data bit
 2710 res%=res% AND &1E
 2720 REM report any problems
 2730 IF res%=0:ENDPROC
 2740 bad$="sector "+STR$(sector%)+" bad read"
 2750 PROCerr
 2760 ENDPROC
 2770 :
 2780 DEFPROCright
 2790 REM move the cursor right
 2800 VDU 9
 2810 REM get cursor coordinates
 2820 PROCcoord
 2830 REM if cursor drops off right, wrap around to the left
 2840 IF x%>37:VDU 31,5,y%:ENDPROC
 2850 IF x%>29:ENDPROC
 2860 REM don't leave cursor in a gap
 2870 IF x%=28:VDU 9,9:ENDPROC
 2880 IF x%=29:VDU 9:ENDPROC
 2890 IF (x%-4) MOD 3=0:VDU 9
 2900 ENDPROC
 2910 
 2920 DEFPROCsectorids
 2930 REM read sector IDs
 2940 param?0=drive%    :REM drive
 2950 param!1=sectab    :REM address
 2960 param?5=3         :REM num of parameters
 2970 param?6=&5B       :REM read sector IDs
 2980 param?7=track%    :REM physical track
 2990 param?8=0         :REM dummy
 3000 param?9=10        :REM num of sectors
 3010 PROCow(10)
 3020 REM report any problems
 3030 IF res%=0:ENDPROC
 3040 bad$="track "+STR$(track%)+" missing sector IDs"
 3050 PROCerr
 3060 ENDPROC
 3070 
 3080 DEFPROCseek(T%)
 3090 REM seek a track
 3100 param?0=drive%    :REM drive
 3110 param!1=&FFFF     :REM no address
 3120 param?5=1         :REM num of parameters
 3130 param?6=&69       :REM seek
 3140 param?7=T%        :REM physical track
 3150 PROCow(8)
 3160 REM report any problems
 3170 IF res%=0:ENDPROC
 3180 bad$="tack "+STR$(track%)+" missing"
 3190 PROCerr
 3200 ENDPROC
 3210 
 3220 DEFPROCstring(num%)
 3230 REM make 2-byte hex string of a number
 3240 str$=RIGHT$("0"+STR$~num%,2)
 3250 
 3260 
 3270 
 3280 
 3290 
 3300 DEFPROCtrack(T%)
 3310 REM adjust track register
 3320 param?0=drive%    :REM drive
 3330 param!1=&FFFF     :REM no address
 3340 param?5=2         :REM num of parameters
 3350 param?6=&7A       :REM write spec reg
 3360 REM pick correct track register
 3370 IF drive% MOD 2=1:reg%=&1A ELSE reg%=&12
 3380 param?7=reg%      :REM reg
 3390 param?8=T%        :REM value
 3400 PROCow(9)
 3410 ENDPROC
 3420 
 3430 DEFPROCup
 3440 REM move cursor up one line
 3450 VDU 11
 3460 REM get cursor coordinates
 3470 PROCcoord
 3480 REM if cursor falls off the top, wrap around to the bottom
 3490 IF y%<4:VDU 31,x%,19
 3500 ENDPROC
 3510 
 3520 DEFPROCwhichsec
 3530 REM found out lowest sector ID
 3540 lowsec%=sectab?2
 3550 FOR I%=1 TO 9
 3560     IF sectab?((4*I%)+2)<lowsec%:lowsec%=sectab?((4*I%)+2)
 3570 NEXT
 3580 REM display header
 3590 PROChead
 3600 REM display track details
 3610 @%=2
 3620 PRINT TAB(5,5);CHR$131;"you are positioned on"
 3630 PRINT TAB(8,7);CHR$133;"physical track ";track%
 3640 PRINT TAB(8,8);CHR$133;" logical track "?sectab
 3650 REM get a valid sector ID
 3660 REPEAT
 3670     PRINT TAB(0,10);STRING$(38," ")
 3680     PRINT TAB(0,10);CHR$130;"enter sector number (";lowsec%;" - ";lowsec%+9;")";
 3690     INPUT " > "sector%
 3700 UNTIL sector%>lowsec%-1 AND sector%<lowsec%+10
 3710 ENDPROC
 3720 
 3730 DEFPROCwrite
 3740 REM write a sector back to disk
 3750 param?0=drive%    :REM drive
 3760 param!1=data      :REM address
 3770 param?5=3         :REM num of parameters
 3780 REM if deleted data read, write back deleted data
 3790 IF del%<>0:code%=&4F ELSE code%=&4B
 3800 param?6=code%     :REM write
 3810 param?7=?sectab   :REM track
 3820 param?8=sector%   :REM sector
 3830 param?9=&21       :REM one sector
 3840 PROCow(10)
 3850 res%=res% AND &1E :REM mask off delete bit
 3860 REM report any problems
 3870 IF res%=0:ENDPROC
 3880 bad$="sector "+STR$(sector%)+" bad write"
 3890 PROCerr
 3900 ENDPROC