10 REM > MDRtoBIN 1.14
   20 REM (C) J.G.Harston
   30 REM Extract files from MDR files
   40 REM v1.11 - Uses CmdLine library
   50 REM v1.12 - Updated ProgEnv library for BB4Wv6+Brandy
   60 REM v1.14 - Spectrum filename cleaned
   70 REM To do: needs to make a second pass to set dest file addresses
   80 :
   90 ON ERROR REPORT:PROCClose_All:PRINTERL:PROCexit(ERR):END
  100 A$=FNOS_GetEnv+" ":PROCf_init:IFos%>31:PROCWin_TextIO
  110 seclen%=543:DIM ctrl% 31,name% 80,secbuf% seclen%-1,type$(4):X%=ctrl%:Y%=X%DIV256
  120 type$(0)="Print":type$(1)="Basic":type$(2)="Num  ":type$(3)="Char ":type$(4)="Bytes"
  130 IFA$=" ":INPUT "Source microdrive file:  "in$:INPUT "Destination dir: "outd$:INPUT "Options/flags:    "A$:A$=in$+" "+outd$+" "+A$
  140 dst%=FNcl("-d",0):ro%=FNcl("-r",0)
  150 REM CmdLine bugfix requires space before final option
  160 A$=A$+" ":vb%=FNcl("-v",0)
  170 in$=FNcl("",1):outd$=FNcl("",1):IFoutd$<>"":IFRIGHT$(outd$,1)=d$:outd$=LEFT$(outd$,LENoutd$-1)
  180 IFin$="-?":PRINT"Usage: MDRtoBIN <src> (<destdir>) -d -v -ro":PROCexit(0):END
  190 IFin$="":PROCexit(0):END
  200 :
  210 in%=FNf_openin(in$):IFin%=0:PRINT"File '"in$"' not found":PROCexit(214):END
  220 IFoutd$<>"":PROCf_cdir(outd$):outd$=outd$+d$
  230 IFvb%:PRINT "Filename   Type  Start Extr  Line  Len";
  240 REPEAT
  250   PROCf_gbpb(4,in%,secbuf%,seclen%,0)
  260   secbuf%?14=13:SpTitle$=$(secbuf%+4)
  270   SpFlag%=secbuf%?15
  280   SpRec% =secbuf%?16
  290   SpNum% =(secbuf%!17)AND&FFFF
  300   secbuf%?29=13:SpName$=$(secbuf%+19)
  310   IF SpRec%=0:PROCRdHeader ELSE PROCRdData(0)
  320 UNTILEOF#in%:CLOSE#in%:in%=0:IFvb%:PRINT
  330 PROCexit(0):END
  340 :
  350 DEFPROCRdHeader
  360 IF SpFlag%=0:IF SpNum%=0:ENDPROC
  370 SpType% =secbuf%?30
  380 SpLen%  =secbuf%!31 AND &FFFF
  390 SpStart%=secbuf%!33 AND &FFFF
  400 SpExtra%=secbuf%!35 AND &FFFF
  410 SpLine% =secbuf%!37 AND &FFFF
  420 IF SpType%=0:SpStart%=SpLine%
  430 IF SpType%=1:SpExtra%=SpStart%:SpStart%=256*secbuf%?35+secbuf%?36:REM Bigendian
  440 IF SpType%=2:SpExtra%=SpStart%:SpStart%=256*secbuf%?35+secbuf%?36:REM Bigendian
  450 IF (SpFlag% AND 4)=0:SpType%=-1:SpStart%=-1:SpExtra%=-1:SpLine%=-1
  460 IF vb%:PRINT'FNfn_clean(SpName$)" ";:IF ro%:PROCHeaderRO ELSE IF vb%:PROCHeaderZX
  470 IF SpType%=-1:PROCRdData(0) ELSE PROCRdData(9)
  480 ENDPROC
  490 :
  500 DEFPROCHeaderZX
  510 IF SpType%<4:PRINT type$(SpType%+1); ELSE PRINT " &"FNh0(SpType%,2)" ";
  520 PRINT " "FNh0(SpStart%,4)"  "FNh0(SpExtra%,4)"  "FNh0(SpLine%,4)"  "FNh0(SpLen%,4);
  530 ENDPROC
  540 :
  550 DEFPROCHeaderRO
  560 PRINT FNhi(SpType%);FNh0(SpStart%,4);" ";FNhi(SpType%);FNh0(SpExtra%,4);" ";FNh0(SpLen%,4);
  570 ENDPROC
  580 :
  590 DEFPROCRdData(off%)
  600 IF SpFlag%=0:IF SpNum%=0:ENDPROC
  610 SpTitle$=FNs(SpTitle$):SpName$=FNs(SpName$):out$=outd$
  620 IF SpName$="":PRINT"null":ENDPROC
  630 IFdst%:IFSpTitle$<>"":out$=outd$+FNfn_unspec(SpTitle$):PROCf_cdir(out$):out$=out$+d$
  640 out$=out$+FNfn_unspec(SpName$)
  650 out%=FNf_openup(out$):IFout%=0:out%=FNf_openout(out$)
  660 IFout%=0:PRINT"Couldn't open '"out$"'":ENDPROC
  670 ptr%=SpRec%*512:IF SpRec%>0:IF SpFlag% AND 4:ptr%=ptr%-9
  680 PROCf_gbpb(1,out%,secbuf%+30+off%,SpNum%-off%,ptr%)
  690 CLOSE#out%:out%=0:IF SpRec%<>0:ENDPROC:REM Set attrs when record 0
  700 IF SpType%=-1:SpStart%=-1:SpExtra%=-1
  710 A%=FNfile(out$,5)
  720 X%!2=SpType%*&10000 OR SpStart%
  730 X%!6=SpType%*&10000 OR SpExtra%
  740 A%=FNfile(out$,1)
  750 ENDPROC
  760 :
  770 DEFFNfn_unspec(B$):IF B$="":="_"
  780 LOCALB%,C$:A$="""#$%&:<>*.@[\]^{|}~":C$="'?S;+;()+/=(/)'(')'"
  790 IF(os%AND-24):A$=""":<>?*/\|":C$="';()#+..'":IF(os%AND-32):A$="""?*/":C$="'#+."
  800 FOR A%=1 TO LEN B$:B%=INSTR(A$,MID$(B$,A%,1))
  810   IF B%:B$=LEFT$(B$,A%-1)+MID$(C$,B%,1)+MID$(B$,A%+1)
  820   IF MID$(B$,A%,1)<"!" OR MID$(B$,A%,1)>"~":B$=LEFT$(B$,A%-1)+"_"+MID$(B$,A%+1)
  830 NEXT:=B$
  840 :
  850 DEFFNfn_clean(A$):IF A$="":=""
  860 FOR A%=1 TO LEN A$:IF MID$(A$,A%,1)<" " OR MID$(A$,A%,1)>"~":A$=LEFT$(A$,A%-1)+"_"+MID$(A$,A%+1)
  870 NEXT:=A$
  880 :
  890 DEFFNhi(A%)
  900 IF A%<3:=FNh0(A%,2) ELSE =FNh0(-1,2)
  910 DEFFNh0(A%,N%)=RIGHT$("0000000"+STR$~A%,N%)
  920 DEFFNs(A$):IFLEFT$(A$,1)=" ":REPEATA$=MID$(A$,2):UNTILLEFT$(A$,1)<>" "
  930 IFRIGHT$(A$,1)=" ":REPEATA$=LEFT$(A$,LENA$-1):UNTILRIGHT$(A$,1)<>" "
  940 =A$
  950 :
  960 DEFPROCClose_All:*Exec
  970 in%=in%:IFin%:A%=in%:in%=0:CLOSE#A%
  980 out%=out%:IFout%:A%=out%:out%=0:CLOSE#A%
  990 ENDPROC
 1000 :
 1010 DEFFNfile(A$,A%):IFPAGE<&FFFFF:$name%=A$:?X%=name%:X%?1=name%DIV256:=(USR&FFDD)AND&FF
 1020 =0
 1030 :
 1040 DEFPROCf_init
 1050 d$=".":s$="/":IFos%AND40:d$="/":s$=".":IFos%>31:d$="\"
 1060 ENDPROC
 1070 :
 1080 DEFFNf_openin(A$)=OPENIN(FNf_name(A$))
 1090 DEFFNf_openout(A$)=OPENOUT(FNf_name(A$))
 1100 DEFFNf_openup(A$)=OPENUP(FNf_name(A$))
 1110 DEFFNf_name(A$):IFos%>31:LOCALA%,B%:REPEATB%=A%:A%=INSTR(A$,"\",A%+1):UNTILA%=0:IFINSTR(A$,".",B%)=0:A$=A$+"."
 1120 =A$
 1130 :
 1140 DEFPROCf_cdir(A$)
 1150 IF(os%AND40):A$="mkdir "+A$ ELSE A$="cdir "+A$
 1160 IF FALSE THEN
 1170   OSCLIA$:ENDPROC
 1180 ENDIF
 1190 LOCAL ERROR:ON ERROR LOCAL:ENDPROC
 1200 OSCLIA$
 1210 ENDPROC
 1220 :
 1230 DEFPROCf_gbpb(A%,chn%,addr%,num%,ptr%):IF num%=0:ENDPROC
 1240 ?X%=chn%:X%!1=addr%:X%!5=num%:X%!9=ptr%:IFPAGE<&FFFFF:CALL &FFD1:ENDPROC
 1250 IFA%=1ORA%=3:PTR#?X%=X%!9
 1260 REPEAT:IFA%=1ORA%=2:BPUT#?X%,?X%!1 ELSE IFA%=3ORA%=4:?X%!1=BGET#?X%
 1270 X%!1=X%!1+1:X%!5=X%!5-1:UNTIL(EOF#?X% AND A%>2)OR X%!5<1:ENDPROC
 1280 :
 1290 DEFFNcl(l$,n%):IFl$="":A$=FNs(A$):IFASCA$=34:A%=INSTR(A$+" "" ",""" ",2):l$=MID$(A$,2,A%-2):A$=FNs(MID$(A$,A%+1)):=l$
 1300 IFl$="":A%=INSTR(A$+" "," "):l$=LEFT$(A$,A%-1):A$=FNs(MID$(A$,A%+1)):=l$
 1310 IFn%=0:IFl$<>"":A%=INSTR(A$,l$):IFA%:A$=FNs(LEFT$(A$,A%-1)+MID$(A$,INSTR(A$," ",A%)+1))+" ":=TRUE
 1320 IFn%=0:IFl$<>"":=FALSE
 1330 A%=INSTR(LEFT$(" ",ASCl$=32)+A$,l$):IFA%=0:=""
 1340 A$=LEFT$(A$,A%-1)+FNs(MID$(A$,INSTR(A$," ",A%)+1))
 1350 IFASCl$=32:l$=MID$(A$,A%):A$=LEFT$(A$,A%-1):=MID$(l$,1-(ASCl$=34),LENl$+2*(ASCl$=34))
 1360 IFASCMID$(A$,A%,1)<>34:l$=MID$(A$,A%,INSTR(A$+" "," ",A%)-A%):A$=LEFT$(A$,A%-1)+MID$(A$,A%+LENl$+1):=l$
 1370 l$=MID$(A$,A%+1,INSTR(A$+""" ",""" ",A%+1)-A%-1):A$=LEFT$(A$,A%-1)+MID$(A$,A%+LENl$+3):=l$
 1380 DEFFNs(A$):IFLEFT$(A$,1)=" ":REPEATA$=MID$(A$,2):UNTILLEFT$(A$,1)<>" "
 1390 IFRIGHT$(A$,1)=" ":REPEATA$=LEFT$(A$,LENA$-1):UNTILRIGHT$(A$,1)<>" "
 1400 =A$
 1410 :
 1420 DEFFNOS_GetEnv:LOCALA%,X%,Y%,P%,A$:X%=1:os%=((USR&FFF4)AND&FF00)DIV256:DIMX%TRUE
 1430 IF!PAGE=&D7C1C7C5:run$=ARGV$(0):IFARGC:FORA%=1TOARGC:A$=A$+ARGV$(A%)+" ":NEXT:=LEFT$(A$,LENA$-1)ELSEIF!PAGE=&D7C1C7C5:=""
 1440 IFPAGE>&FFFFF:DIMX%LOCAL256:A$=@cmd$:SYS"GetModuleFileName",0,X%,255:run$=$$X%:Y%=INSTR(@lib$,@tmp$)=0:P%=TRUE
 1450 IFP%=0:IFHIMEM>&FFFF:run$=$&8100:SYS"OS_GetEnv"TOA$,,A%:SYS"OS_WriteEnv","",A%:A$=MID$(A$,1+INSTR(A$+" "," ",1+INSTR(A$," "))):P%=TRUE:Y%=TRUE:IFINSTR(A$," ")=0:A$=run$+" "
 1460 IFP%=0:P%=X%:[OPT 0:NOP:]:P%=?X%:Y%=TRUE:IFP%=&EAORP%=18:A$=$&600 ELSEIFP%=0:A$=$(PAGE-&300)ELSEIFP%=&A0:A$=$(^@%-256):Y%=?(PAGE-2)AND64ELSEIFP%=&90:A$=$&100:Y%=!&200
 1470 A$=" "+A$:REPEATREPEATA$=MID$(A$,2):UNTILASCA$<>32:IFASCA$=34:A%=INSTR(A$,"""",2)+1ELSEA%=INSTR(A$+" "," ")
 1480   IFY%:run$=LEFT$(A$,A%-1):A$=MID$(A$,A%+1):Y%=0
 1490 UNTILASCA$<>32:=A$
 1500 :
 1510 DEFPROCos(A$):IFASCA$=42:OSCLIA$ ELSE IFA$<>"":CHAINA$
 1520 ENDPROC
 1530 :
 1540 DEFPROCexit(A%):OSCLI"FX1,"+STR$(A%AND255):quit$=quit$:A$=quit$:quit$="":PROCos(A$)
 1550 IFPAGE>&FFFFF:QUIT A% ELSE END
 1560 ENDPROC
 1570 :
 1580 DEFPROCWin_TextIO
 1590 SYS "GetStdHandle",-10 TO @hfile%(1):*INPUT 13
 1600 SYS "GetStdHandle",-11 TO @hfile%(2):*OUTPUT 14
 1610 SYS "SetConsoleMode",@hfile%(1),0:ENDPROC
 1620 :