PATRANS-01INCS/TRANS-02INC0sTRANS-03INC TRANS-04INC2TRANS-05INC:TRANS-06INC*NTRANS128COMTRANS128DOC5:TRANS128PAS] ͫCopyright (C) 1985 BORLAND IncBKaypro, no hiliteeedP=  E RC1B1~7#~=  oͦlԅ!!"~#(}:$= +*!6!*!!:(2!6:(>2!!!:O::O:!*! !45(! +/ 0y0( d!k6!{6``o&  :(͠|(  *"x2y( >28!"9!! og2"">~22!:05+:!Co&ͦͣ} [ (!e|ͧA8Q0G: x@!\w# (̓ ?(*( .( x_. _!h6# (?( *( ̓( w#>?> w#ͧ 8 !ɿ .,;:=?*[]<>{}a{ |͵};Ɛ'@'7||}>2Ͱ*Bک  "og"2>2! ""*B"[Rv*"^#V#^#V#N#FO/o&9O/o&9!9(> (G!9 w#Eͻw}8( RB0 >( RrRR!+ ͱ R!+ ͱ s!+ ͱ s!+ ͱ s!# ͱ s!+ ͱ T]KB!z> S>))0 = | |́́DMgo>jB0 7?= H͓<z5b)b<z {0Gɯgo||}||/g}/o#}o&K[xAJSJDM!b"!6J"DM'd } * W _}8(8J`9{T]=o`9y *  >( ͂ ͭ͘ }>( x‰ }} ˸T}ٕ(0D={ ,= ( ͓ 0%| , 7 ?(8ͭ x ͇ - s 8˸x ͐  ,-xG}s }مN 9s .>#n0͓ | = - nx ͈ ,-(-˸G,-s }ٕ?N 9.> 8ͭ ?= u+-(>͇ 0ͭ ͇ 8 ?x ͈ , 78ƀ8ƀ8ox٨!دoGOW_gɷɷ|لg{ً_zيWyىOxوG|ٔg{ٛ_zٚWyٙOx٘Gxٸyٹzٺ{ٻ|ټx٨ xx( ?}ٽ }ցs <(s 7| = |٤g{٣_z٢Wy١Ox٠G| ͭ ͂ }x>( ͭ}ƀ/ƀo  -͂ }0͏-͂ ͏,}l˸ 8 5 ͘ x( - 8͂ - 8,͂ }l8;*!͘ ! >5ͭ͘ ͘ ͭ--- ͂ ,,,-xGg?+2n*8t z~,->( x( ͙}. ͇͂ , ! >5,ͣ- o&0% ,͘  }gs }؉}颋.:}8c~I$I~L*ͣٷx˸ }0G,<} ,-(-͂ !>J0 ͙͘ o8 ͇ >( m.`1pF,t6|!wS<.z}[|%FXc~ur1}͇ٯx(<˸ 8 !~J 0/O!>t 8 =  o t͘ ͇ /o 0 ͏-͂ OT0 j oD,:j !I}袋.}8c~I$I~L! >ͭ͘ JØ oo ͘ = ͇ nf^VNF!DLT\I!!53!r1!͓!> x #-= o˸x͇(- }(x>8({ ,{ `iÄ!>( |s |́>)=|(DMbo˸88x(0 8> ́x(>-{(ay( z(>. ( {>E>+|(|Dg>-|/ 0:p# ~# +>0w#,-  60#~˸}րogM| .({ = ~> x0w#xG%͈ %͈ ZJDM%͈ = _~65+~hìx-Sx9?+{Η@}|{ { gZJDM0| ,7}o˸@ #yO!@9i&@  #@w#@/w#@w#!9! E9!!9~(+Fͻ!"9!(#>2*"| >"2:( ͷ *w*6 !\$![ (ͧ( #:~CONTRMKBDLSTCAUXUSR>2j:*ˮ~1:*:(@q##p[* :(  ~* < >26"!"""~>2""v>2>"!"ˮ(!~8>~O6~*"w(6(2(-()(6 (8 0 :(* y(~#+ (( 66 #6 #"*: y~o p .##~ͻ(.6w4._~ =*##55= *[R8*~#"= ͣ}== ͯ}͵}*#w+#~+>*~('l!0(ˮ]l!8ˮ!]~-#8~>27lˮw>O%7̄s #r%ͤ7̐ l ( (ˮ ql(ˮ ( l ˮ*O:~ ##~._q4((=ʦ==ʩ=ʬò*:4^q*##~6ͻ>2}*|(̈́|( ̈́6-#[RM8( G> A~#*(C! !TRUEFALSE!9N#Z~#( G~#> >    "~(lѻ(( !0 (ˮ!!>2S{:1:*6##ww#w$w#w:  ##N#F*B>2w#w#[s#r> "~ͯ*-w#ww##> ͯÂ""~>2:[R0 *4#4>2:[R> *4 #4(> >22*f(/˦:G(##~++ :O x yD!ͻ Q*:G(##~._.͛g<]=<͛*##w ͯ +4 #4x>>2:G("ͯ"*nˮ*0 S[ѷR8@* N#F#s#r- 0})jS\*##w+ N#FB ͯr+s>2!T]>)j)0 0= ^R!#^*^#V#N#F#^#V>2ͱ:1:*6 #-Nw#Fwq#p#6#w#w#w"~Â>">!DM!":*B:!>(>2>">!"2"~ʱ*w#wx(9* :O *-4 #4!*4 #4 *-N#Fq#pV+^Bq#pS[ѷR'* s#r$ s#rM <?*M!\  <( !\$>2>2M:>!(* \$\<(!4: [1ð\!(7"~> 2"S"Ns#FrB(Z#\: \<(?*"}K\! !*}#"}! x \* *>* 2""{_!"*nf}(HR0nf" ^VMDnfutqp*s#r*s#r"* vKB!1>( ~#fo{_"*R0RnfR0KqputsrNF( ^VNF^V*SutKqp R*R(~w~wnf ut"6#L*L*!""*NFy(* "*B0Cnf* [R*"*RS[s#r^#V""6#>O"w2x2*"!G"" 'z*"*>2"*"!G"""!\*: Os!~6go(\R*s#r_2x( s x(T]DMx(R0 U(͞O/o&9q# (!>F0#( ~ ( #]( ~ ( (#}(  i&T-a%ã}ͧo*!~6o&|:2!2}:__{ѯ2*|KB " z ^C User break+=  I/O Run-time error {͵, PC=*ͰNot enough memory Program aborted :m'1!e!_ScB>]"Eg"Gg"Ig}2Kg}2Lg*!0Eʕ!*Lg& RV!RV!RV!Rt!*Lg&!R*IgDM"MgÒ!*Lg&!R*IgDMo&"MgC"!Og"=g!Og!!O*Lg&*=gs*=g*Kg&s*=g*Igs#r*=g*Ggs#r*=g*Egs#r*Lg& R"R"R"R1"!2!Og"MgC"!2!Ogo&"Mg*MgI ?oMSDOS-1 DSI ?MSDOS-1 SSK$go MSDOS-2 DSK$? MSDOS-2 SS"9g";g*_*;g! "]!!gz-#"/g!!*9g*/gn&*]*/g!!"c*/g#"!g!}2e!*e.!g;ͳ!Ee#!}2e" g" g"g"g*g*g*g* ggzʭ#"g͜!*# *g#Ï#*g* ggz#"g* g*g͜!*# *g#ø#*g* g* g*gwz$"g͜!*# *g+#* g*gwzF$"g*g*g͜!*# *g+$?! !!<!f#͜ͻ* TRANSFER - vers ͻ1.2Cͻ - Commodore 128/1571  !!͜ͻ CP/M= *.!A#!:# ͜ͻ MS-DOS= *0!A#!:# !! ͜ͻ"1. Transfer File: CP/M ==> MS-DOS !! ͜ͻ"2. Transfer File: CP/M <== MS-DOS !! ͜ͻ 3. Directory of MS-DOS Disk !! ͜ͻ 4. Allocation Map MS-DOS Disk !!͜ͻ5. Directory of CP/M Disk !!͜ͻ 6. Erase File MS-DOS Disk !!͜ͻ7. Restore FAT !!͜ͻ 8. Rename File MS-DOS Disk !!͜ͻ 9. Format Disk MS-DOS Disk !!͜ͻ 0. View Text File MS-DOS Disk !!͜ͻ' Enter Your Selection ( to Quit):  !ͪ!fE *f&͂!͒!0!9͜PE&*f&}2f*f&͜ͻPress [Return] to Continue.. !ͪ!fE *f&!̀Eʾ'!}2f*f&! ̀Eʖ'"f"f*f^#V!*fs#r*f^#V*ͦE#(!*fs#r*f^#V!*fs#r͜ ͜ͻDisk I/O Error,  p'}2f"f*6&!0̀*f*.̀}o}oE8)*!0ͦEʚ(!*f*f&E(! !*f!!!"c(! !*f!!!"c*c!̀}2i!E8)͜ ͜ͻ DriveCode=*f!'ͻ DPH Address=*c!' "f"f"f*#!"f*!0ͦEm)!"f!}2i!*f!Rgzv*"f! !*f!!!"c!E)!!*f*f*f!!!!"f)*f*f*f!"f! !*f!!!"c! !*f!*f!!!"c*i&! !!!!!!͓}o}2i*f#È)*i&Eʃ*$("f"f"f*#!"f*!0ͦEʸ*!"f!}2i!*f!Rgz+"f! !*f!!!"c!E/+!!*f*f*f!!!!"fI+*f*f*f!"f! !*f!!!"c! !*f!*f!!!"c*i&!!!!!!!͓}o}2i*f#**i&E+$(*!!'9)*!!!'*#9)*"f!"f!*%!RgzT,"f*f*f!'*#*f̈́*!f!f'*f#,"f"f*f!R"f*f*'*"~f*f*'*F"f*f*"f*~f**f*"~f*f*F"f!*'!Rgz%-"f*f*~f!]g*f*#*f+9)!f!~f'*f#,"zf"|f*|f!R"|f*|f*'*"lf*|f*'*F"nf*nf*"nf*lf**nf*"lf*nf*F"nf!*'!Rgz-"pf*nf*lf!]g*pf*#*zf+̈́*!nf!lf'*pf#õ-"hf*hf!!!"\f!'*\f+n&!!'*\f!+n&"^f*hf͌Eb.*^f!W"^f*^f!|g}o"jf*jf͠E.!ͪ!QfE *Qf&!̀Eʾ.͠}oEʯ.à.!ͪ!QfE *Qf&!̀E.!}2Zf.!}2Zf.!}2Zf*Zf&"8f":f!/!! to abort):  !ͪ!`eE *`e&͂! ͒!1͒!2͒PE8*`e&͜# *`e&! ̀E9Ñ9*`e&!0R"%!*%"^e!"\e!*%!Rgzʋ9"Ze*^e*\e!'*#*Ze9)!^e!\e'*Ze#Q9+p'}2Be"Ce!Ee!!8!Ee;!!.*.!}2!}2!}2*Be&E9!!o&"8e:!!o&"8e*8e!̀E-:!*Ces#rÙ:!*Ces#r*8e!|g}o! !"8e!!!gzʙ:"6e!*6e!8*8e+*6en&s*6e#g:*.!K(!"*e?͜ ͜ͻ Dir Mask:  !e͏ ͜ !e;!,e!͒9*,e!̀E;͜ͻ No File,  p'B<**e!F!̀E@;͜ O;͜ͻ :  *-&͜#!:# !!gzʖ;"(e!*(e+n&͜# *(e#n;͜!.# !!gz;"(e!*(e+n&͜# *(e#í;**e!"*e!e;!,e!͒9*,e!̀w.}oE;͜ ͜ ͜ͻ File Count: **e!' p'" e"e*e!!!"e!'*e+n&!'*e!+n&!O|g}o"e*e͌E<*e!|g}o* e!O|g}o"e<*e!|g}o* e!|g}o|g}o"e!'*e+*e!|g}os!'*e!+*e!W!|g}osîAN!d!!gzʪ="d!*d+n&! ̀}oEʡ=!d;!*d+n&e.>!d*d#X=!d;!.e.>!d!!gz>"d!9! e.͎}oE>!d;!*d+n&e.>!d*d#="d*d"d*d*!*d-!͓}oEd>*d!"d+>*d"d*d*!̀Eʇ>!}2i*d*d!x!Eʴ>!x!"dú>*d"d!]g!x!O!!]g!+*dͿ !E?͜ͻNRecs=*d!' *d*d"Yg*d*dF!E8?*Yg!"Yg!*Yg!Rgzʪ?"d*d*d!>C<*d*d*d!!&-*d"d*d!>"d*d#L?ddN ????????.???!qd!}2h!}2g!qd;!dͅ5*d!͓*d!͓}o*h&}o*g&}oE8@!qd;!dͥ2?*d!̀ER@!}2i@!d[*!d* ! s! !gzʲ@"d* *d!s*d#È@*!s#r*!s#r!>"d**ds#r"od*od!Wl&"ed*od!|g}o!O"od*!+*od&s*!+*odl&s*!+*ed&s*!+*edl&s*od!̀EʐAÛA*d!C<** !̈́*+?͜ ͜ͻ!File Transfer From CP/M to MS-DOS ͜ ͜ͻFile Name to Get From CP/M:  !d͏ ͜ !:e.!d;ͳ!͓}2f*f&EʛB͜ͻ DriveCode = *-&# ͜ͻ, Do Not Include In Name. p'*f&}oEʮA!}2f!d;.#*.!K(!d;!d!͒9*d!̀EC͜ͻFile Not Found,  XFA=!!d;q!q !^"d!ELC͜ͻ FileSize=*d!' ͋>6*&!̀E{C*.!K(!ͱ XF͜ͻ Transfering - *!*'"d!d;!d5͜ *-&!:e.ͣ >͜!ͫ!d;!ͫ *d!̀E D͜ͻ Exists !}2fE!!ͫ?!E(D͜ *f&w.}o}2f*i&}o*f&}o}oEE?*f&*i&}ow.}o}2f*d*dR"d*d!*f&}o}oED*.!K(͋>*0!K(?*i&*f&}ow.}o}2f*d*dR"dÂD*f&}oEE!^@*.!K(!ͱ *f&w.}o}2f*i&E|E!}2f͜ ͜ͻ,MS-DOS Write Error or Disk or Directory Full F*e&*f&}o}oEF!d;!d!͒9!d;!d!͒9*d!̀EFA=!!d;q!q !^"d!EF͜ͻ FileSize=*d!' ͋>*0!K(*d!̀*f&}o*e&}o}oEʠC͜ ͜ *f&EuF͜ͻ Aborted,  p'*.!}2*!!e*!!e!!+n&"4*4!|g}o"4!!+*4s!!gzG"4!*4!s*4#F!*!+n&!|g}oR}2!!"Yd*Yd!R!"Od*Yd!R!F!EʇG*Od!"Od*Od"[d*[d"Gd*Gd!+n&!*Gd!+n&   !! *Gd!+n&  !! ! *Gd!+n&  !Id!Id-!"5d*5d*[g*f&}o}oEI!]g*5d+n&"3d*3d! ̀*3d! ̀}o*3d!*3d!}o}oEH!]g*5d+n&͜# *f&w.}o}2f*5d!"5dyHdI*Yg!EWI*Yg!R"Yg*[g*c!"[gcI*[g*Wg"[g6*&!̀}oE,O?͜ *6&!2̀EI͜ͻ!File Transfer From MS-DOS to CP/M I͜ͻView a Text File on MS_DOS Disk ͜ ͜ͻFile Name to Get From MS-DOS:  !d͏ ͜ !}2f!d;.#!d;!c5*h&*g&}oEʁJ!d;!c5]J*c!̀EʮJ͜ͻFile Not Found,  O͜ͻ Transfering - *!*'"c*.!K(N!d!!gzJK"c**c+n&! ̀}oEAK!d;**c+n&e.>!d*c#J!d;!.e.>!d!!gzʥK"c!d;**c+n&e.>!d*c#mK*6&!2̀EK*-&e.!:e.>!d;>!d!d;͜!ͫ *6&!2̀EL!j!d;q!jp cL͜ ͜ͻ)Press to pause, to abort - ͜ *f&w.}o}2f*f&}oEZN*^#V"c*͑G!c!c-*c!  "Yg!c-*Yg*c!  "Wg!]g!x!O!"[g*0!K(*c!*f&}o}oEM*c*[gU,!I*[g!R!x*c!REM*.!K(*6&!2̀EʱM!j!]g!+*[g;Gͻ ôMsH*0!K(!]g!x!O!"[g*c-"cM*.!K(!]g*[g+!s*6&!2̀EIN!j!]g!+*[g;Gͻ !jͱ *!0EFNyFZN*f&}oEZNsH*f&w.}o}2f*e&*f&}o}oEN*0!K(!d;!c5*h&*g&}o}oEʎN*c!̀}oEN*.!K(*c!̀*f&}o*e&}o}oEJ͜ ͜ *f&E)O͜ͻ Aborted,  p''...JanFebMarAprMayJunJulAugSepOctNovDec!/Oc'!"c6*&!̀}oE&T?͜ ͜ͻ Dir Mask:  !c͏ ͜ ͜ͻNameN Attrubutes!ͫNClstr!ͫNDate! ͫNTime! ͫNSize!ͫ !!<gz>P"c͜!-# *c# P!c;!c5*c!̀ES͜ *c!"c*"c!!gzʩP"c*c*c+n&͜# *c#ÁP͜!.# !!gzP"c*c*c+n&͜# *c#P͜ͻ  *c n&"c*h&E$Q͜ͻ ÓQ*g&ECQ͜ͻ ÓQ!!gzʓQ"c͜*c!W!|g}o!0# *c!O"c*c#NQ*c^#V͜!' ͜ͻ  *c^#V!W!|g}o"c*c! EQ!"c*c!"c*c*c!gz4R"c!c*cn&͜# *c# R͜! # *c^#V!|g}o"c*c! EuR͜!0# *c͜!' ͜!,#*c^#V! W!!' ͜ͻ  *c^#V! W"c*c! ER͜!0# *c͜!'!:# *c^#V!W!?|g}o"c*c! EBS͜!0# *c͜!'!:# *c^#V!|g}o!"c*c! EʕS͜!0# *c͜!' ͜ͻ *c͑G!!z !c;!c5*c!̀w.}oEKP͜ ͜ ͜ͻ File Count: *c!' p'6*&!̀}oEʿT?!*!RgzʪT"4*4!F!̀EʁT͜ ͜*4!-!'!,# *4#WT͜ ͜ p'PU&''&' ' "c!!s!!s!! s!!gzOU"xc!*xc!T*c)))*xcn&s*xc#U!o&!͓E>V͜ͻ0Formatting MS-DOS disks will be done in Drive A. ͜ͻ@Insert a scratch CP/M disk in Drive A first, just to log onto it ͜ͻ4before proceeding with a blank disk to be formatted. !!K(͜ ͜ͻ'Enter the type of disk to be formatted: ͜ ͜ͻ# 1 : MSDOS-1 DS (8 sec/trk) ͜ ͜ͻ# 2 : MSDOS-1 SS (8 sec/trk) ͜ ͜ͻ# 3 : MSDOS-2 DS (9 sec/trk) ͜ ͜ͻ# 4 : MSDOS-2 SS (9 sec/trk) ͜ ͜ ͜ͻWhich one (1 - 4)?  !ͪ!cE *c&͂!1!4͜PEʎW*c&͜# *c&!1R"c!'!+*c}/o|/gs!}2f͜ ͜ͻA *** Insert a blank disk to be formatted in drive A now *** ͜ͻType $ to begin formatting.  !ͪ!cE *c&!$̀EuX*c&͜# *cT!!!!!!"c!n&!͓}2f*f&EY͜ͻError Formatting íY!!K(!!!O!!+!'!+n&s!"*c!!"%*!!̈́***%!!̈́*͜ *i&}oEʭY͜ͻFormatting complete p'! 6*&!̀}oE]?͜ *6&!6̀EZ͜ͻ File Name to Erase From MS-DOS:  @Z͜ͻOld File Name on MS-DOS:  ![c͏ ![c;ͤ!̀EgZ]͜ !}2f![c;.#![c;!Uc5*Uc!̀EʺZ͜ͻFile Not Found,  ù]*6&!8̀E,\!*e.![c;ͳ!͓!?e.![c;ͳ!͓}oE []!}2f͜ͻNew File Name ( to abort):  ![c͏ ![c;ͤ!̀E`[]!![c;ͤgz["Wc![c*Wcn&͂!$͒!%͒!+͒!-!9͜!A!Z͜!_͒!a!z͜P}oE[!}2f*Wc#q[*f&}oE [![c;**.** !̈́**!0E&\! p']͜ͻ Erasing - !!gzʓ\"Wc**Wc+n&! ̀}oEʊ\**Wc+n&͜# *Wc#M\͜!.# !!gz\"Wc**Wc+n&͜# *Wc#ê\͜ *^#V"Sc*Sc*͹E>]*Sc"Yc*Yc"Sc*Sc-"Yc*Sc!C<*Yc**Yc!̀}oE]*!+!s** !̈́**e&Eu]![c;!Uc5w.}2f*Uc!̀*f&}o*e&}o}oEB\+͜ ͜ *f&E]͜ͻ Aborted,  p'?! "!o&"2*2".!!͜ͻ#Which Drive is the MS-DOS Disk in?  !ͪ!6E ͜*6&#!:# *6&!AR"0͜ *.!A}2-*0!*0!ͦ}o}oE]͜ !!Fn&!F!n&!"_!!gz_"4!*4!G"*4)))))"*4#^!}27G$}26?*6&1R4_>=_0RH_2RN_I_3R^_-O_4Rn_'T_5R~_͚:_8Rʒ_6R˜_͹Y_7R¨_F8_9R¸_T_R_!}27*7&E_! !*. Tf_5R5͚:v_ (*********************************************************) (* *) (* TRANSFER.PAS (version 1.0) - *) (* a program to transfer files between cp/m and ms-dos *) (* with a cp/m host system *) (* *) (* Written by David Koski 1985 *) (* P.O. Box 1078 *) (* Fort Bragg, CA 95437-1078 *) (* 707/964-0806 *) (* *) (* This program is intended for private non-commercial *) (* use and is considered to be public domain material *) (* *) (*********************************************************) (* *) (* TRANS128.PAS (version 1.2C) - *) (* Modified/enhanced for C-128 with single 1571 drive: *) (* Format MS-DOS disks, *) (* Rename MS-DOS files, *) (* View MS-DOS text files. *) (* *) (* by B-J Lee 1987 *) (* 1021 Merritt Dr. *) (* Tallahassee, FL 32301 *) (* CompuServe [71171,3260] *) (* *) (*********************************************************) program Transfer; const SecTrans = false; { sector translation for bios read/write } SO = 0; { offset added to sector number } DEBUG = false; DataBufferSize = 30720; { 30 K bytes } MinSector = 0; MaxFATSize = 1024; Vers = '1.2C'; SectorSizeMax = 512; BufferSize = SectorSizeMax; MenuMargin = 18; {ClusterSizeMax = 2048;} SizePC_FCB = 32; SizeCPM_FCB = 32; NameSize = 8; TypeSize = 3; First = true; Next = false; EODirectory = $FF; MTDirectory = 1; FoundDir = 0; SELDSK = 9; { BIOS calls for CP/M+ } SETTRK = 10; SETSEC = 11; SETDMA = 12; RDSEC = 13; WRSEC = 14; SECTRAN = 16; DEVTBL = 20; DRVTBL = 22; FLUSH = 24; USERFUN = 30; GETVSN = 12; { BDOS calls } RESETDSK = 13; LOGDSK = 14; SearchF = 17; SearchN = 18; CURDSK = 25; SetDMAF = 26; SETATT = 30; COMPUTESIZE = 35; CALLBIOS = 50; type SizeArray= Array[1..4] of Byte; Str20 = string[20]; Bufr = array[1..BufferSize] of char; {CBufr = array[1..ClusterSizeMax] of char;} FATarray = array[1..MaxFATSize] of byte; FAT_ID = (Unidentified,ss8spt,ds8spt,ss9spt,ds9spt,B_20); NameAry = array[1..NameSize] of char; TypeAry = array[1..TypeSize] of char; NameStr = string[20]; PC_FCB = record Name: NameAry; Extention: TypeAry; Attribute: byte; Rsrvd: array[12..21] of byte; Time: integer; Date: integer; ClusterNo: integer; FileSize: SizeArray; end; CpmFCB = record DriveCode: byte; {0=default, 1=A, 2=B...} Name: NameAry; Extention: TypeAry; Extent: byte; S1,S2: byte; RC: byte; Rsrvd: array[16..31] of byte; CR: byte; R0,R1,R2: byte; end; var CPMversion: integer; CPM_Buf: array[1..128] of char; Done: boolean; Selection: char; I: integer; DefaultDisk: integer; MS_DOS_Drive: integer; CPM_Drive: integer; CPM_DriveCh: char; Track: integer; Sector: integer; SecsPerCluster: integer; FAT: FATarray; FATSize: integer; SectorSize: integer; RecordsPerSector: integer; DirSecs: integer; NTracks: integer; NSectors: integer; NClusters: integer; Identity: FAT_ID; FirstFATSector: integer; FirstDirSector: integer; FirstDataSector: integer; FirstDataTrack: integer; DirSector: integer; DirTrack: integer; DirSectorCount: integer; SingleSided: boolean; DOS_FCB: ^PC_FCB; CPM_FCB: CpmFCB; Buffer: Bufr; DirBuffer: Bufr; DirOffset: integer; DirName: NameStr; {ClusterBuffer: CBufr;} MaxSector: integer; InFile: File; CPMFile: File; BiosError: boolean; VolumeName: boolean; SubDirName: boolean; Stop: boolean; Wildcard: boolean; D: integer; {a dummy for function bios3()} UnusedBytes: integer; {# of unused bytes in the last record} MFMTablePointer: integer; BankZeroAddress: integer; DataBuffer: array[1..DataBufferSize] of char; BufferIndex: integer; NumberOfClusters: integer; ExtraBytes: integer; type BiosPB = record func: byte; aVal: byte; bcVal: integer; deVal: integer; hlVal: integer; end; var Bios_PB: BiosPB; function bios3(fn,aReg: byte; bcReg,deReg,hlReg: integer): integer; begin if (CPMversion < $30) then begin case fn of 9,16,20,22: bios3 := bioshl(fn-1, bcReg); else bios3 := bios(fn-1, bcReg); end; end else begin with Bios_PB do begin fillchar(Bios_PB, 8, 0); func := fn; aVal := aReg; bcVal := bcReg; deVal := deReg; hlVal := hlReg; case fn of 9,16,20,22: bios3 := bdoshl(CALLBIOS, addr(Bios_PB)); else bios3 := bdos(CALLBIOS, addr(Bios_PB)); end; end; end; end; type MFMEntry = record classification: byte; format: byte; xlt: integer; spt: integer; bsh: byte; blm: byte; exm: byte; dsm: integer; drm: integer; al0: byte; al1: byte; cks: integer; off: integer; psh: byte; phm: byte; pspt: byte; DiskType: array[1..10] of char; end; const MS_DOSType: array[0..3] of MFMEntry = ((classification:$49; format:$A3; xlt:0; spt:$20; bsh:3; blm:7; exm:0; dsm:$13F; drm:$6F; al0:$C0; al1:0; cks:$10; off:0; psh:2; phm:3; pspt:8; diskType:'MSDOS-1 DS'), (classification:$49; format:$A5; xlt:0; spt:$20; bsh:3; blm:7; exm:0; dsm:$9F; drm:$3F; al0:$C0; al1:0; cks:$10; off:0; psh:2; phm:3; pspt:8; diskType:'MSDOS-1 SS'), (classification:$4B; format:$A3; xlt:0; spt:$24; bsh:3; blm:7; exm:0; dsm:$167; drm:$6F; al0:$C0; al1:0; cks:$10; off:0; psh:2; phm:3; pspt:9; diskType:'MSDOS-2 DS'), (classification:$4B; format:$A5; xlt:0; spt:$24; bsh:3; blm:7; exm:0; dsm:$B3; drm:$3F; al0:$C0; al1:0; cks:$10; off:0; psh:2; phm:3; pspt:9; diskType:'MSDOS-2 SS')); procedure LoadMFMTable(EntryIndex, EntryAddress: integer); var I: integer; begin BankZeroAddress := MFMTablePointer + (EntryIndex * 32); for I := 0 to 31 do D := bios3(USERFUN, 1, mem[EntryAddress + I], BankZeroAddress + I, 0); end; procedure CheckWildcard(Filename: Str20); begin Wildcard := false; if (pos('*', Filename) > 0) then Wildcard := true; end; {$I TRANS-01.INC} {$I TRANS-02.INC} {$I TRANS-03.INC} {$I TRANS-04.INC} {$I TRANS-05.INC} {$I TRANS-06.INC} procedure EraseMS_DOS; {or rename MS-DOS file} var FileName: Str20; NextCl,I,Err: integer; Cl: integer; begin IdentifyMS_DOS; if not (Identity = Unidentified) then begin ClrScr; writeln; if (Selection = '6') then write('File Name to Erase From MS-DOS: ') else write('Old File Name on MS-DOS: '); readln(FileName); if (Length(FileName) = 0) then exit; writeln; Stop:= false; CheckWildcard(FileName); SearchFirst(FileName,Err); if (Err = EODirectory) then begin write('File Not Found, '); end else begin if (Selection = '8') then begin if (pos('*', FileName) <> 0) or (pos('?', FileName) <> 0) then exit; repeat Stop := false; write('New File Name ( to abort): '); readln(FileName); if (Length(FileName) = 0) then exit; for I := 1 to Length(FileName) do if not (FileName[I] in ['$', '%', '+', '-'..'9', 'A'..'Z', '_', 'a'..'z']) then Stop := true; until not Stop; ConvertName(FileName, DOS_FCB^.Name, DOS_FCB^.Extention); WriteSector(DirSector, DirTrack, addr(DirBuffer)); if (CPMversion < $30) then bdos(RESETDSK); {to force disk write} Continue; exit; end; writeln('Erasing -'); repeat for I:= 1 to NameSize do if not (DOS_FCB^.Name[I] = ' ') then write(DOS_FCB^.Name[I]); write('.'); for I:= 1 to TypeSize do write(DOS_FCB^.Extention[I]); writeln; Cl:= DOS_FCB^.ClusterNo; if (Cl <= NClusters) then begin NextCl:= Cl; repeat Cl:= NextCl; NextCl:= FATPointer(Cl); SetFATPointer(Cl,0); until ((NextCl > NClusters) or (NextCl = 0)); end; DOS_FCB^.Name[1]:= #$E5; WriteSector(DirSector,DirTrack,addr(DirBuffer)); if Wildcard then SearchNext(FileName,Err); Stop:= Break; until (Err = EODirectory) or Stop or not Wildcard; PutFAT; writeln; writeln; end; if Stop then write('Aborted, '); Continue; end; end; (********************) (* *) (* main program *) (* *) (********************) begin ClrScr; CPMversion := bdoshl(GETVSN); DefaultDisk:= bdos(CURDSK); {0=A, 1=B...} CPM_Drive := DefaultDisk; repeat gotoxy(1,5); write('Which Drive is the MS-DOS Disk in? '); read(KBD,Selection); write(upcase(Selection),':'); MS_DOS_Drive:= ord(upcase(Selection)) - ord('A'); {0=A, 1=B...} writeln; CPM_DriveCh:= chr(CPM_Drive + ord('A')); until not ((MS_DOS_Drive < 0) or (MS_DOS_Drive >= 16)); writeln; Delay(500); MFMTablePointer := mem[$FD46] + mem[$FD46 + 1] *256; for I := 0 to 3 do {load MFM table into bank 0} LoadMFMTable(7 + I, addr(MS_DOSType[I])); done:= false; repeat Selection:= MainSelection; ClrScr; case Selection of '1': WriteMS_DOS; '0','2': ReadMS_DOS; '3': DirMS_DOS; '4': MapMS_DOS; '5': DirCPM; '8','6': EraseMS_DOS; '7': RestoreFAT; {'8': Done := True;} '9': FormatMS_DOS; #27: Done := true; end; (* case *) until Done; bdos(RESETDSK); bdos(LOGDSK, CPM_Drive); end.  ************************** * TRANSFER DOCUMENTATION * * version 1.0 * ************************** by David Koski P.O. Box 1078 Fort Bragg, CA 95437-1078 I. INTRODUCTION TRANSFER is a utility that provides an easy method of transfering files to and from MS/DOS compatable disks with a CP/M host system. Written completely in Turbo Pascal, it includes these features: - Full Access of directory of MS/DOS with ambiguous file reference - Access to CP/M directory with ambiguous file reference - Display of MS/DOS FAT (File Allocation Table) - FAT recovery from backup FAT (Careful!) - File transfer to and from MS/DOS using PIP-like ambiguous (wild card) file references - Source code - - of course II. INSTALLAtTION After making a working copy of the distribution disk, with your original disk in a safe place you should have the following files: TRANSFER.COM TRANS-01.INC TFR-INST.COM TRANSFER.DOC TRANS-02.INC TFR-INST.MSG TRANSFER.PAS TRANS-03.INC TFR-INST.DTA TRANS-04.INC TRANS-05.INC For screen functions use TFR-INST, a GINST-made instalation program. Install TRANSFER the same way you install TURBO PASCAL. TFR-INST.MSG and TFR-INST.DTA are used by TFR-INST.COM. Now the BIOS in your system must know that your MS-DOS disk is "foreign". Many systems come with a utility to accomplish this. Your BIOS usually not only must know the sector size of the MS- DOS disk (usually 512) but the Density (Double). In short You must "tell" your BIOS that the drive with the MS-DOS disk in it is "IBM-PC DS" or something similar. For reasons mentioned above, TRANSFER is system BIOS dependent. If that wasn't enough, each different BIOS likes to do the BIOS function call Sectran it's own way. Some systems need TRANSFER to call Sectran before each sector read. Also, in some systems a sector bias needs to be applied to each BIOS call from TRANSFER. These variations are accomplished by patching the constants in the source TRANSFER.PAS and recompiling. Some experimenting may be necessary. For example some Kaypros need "SO = 4" to give a sector bias of 4. This is because of 4 CP/M records (128 bytes) are in each 512 byte MS-DOS sector. Many systems automaticly identify newly logged on disks. The trouble is they usually come up with the wrong inentity for the MS-DOS disk and often think it is single sided. If you are unable to patch your BIOS to prevent this then you may be able to use single sided MS-DOS disks only, or trick your system by logging on to a standard double sided disk first. Then without warmbooting, bring up TRANSFER. Systems with single sided drives can of coarse only transfer single sided disks and TRANSFER may need minor modification. ****************************************************************************** ---------- Version 1.2C (for C-128) ---------- This is the Commodore 128 CP/M adaptation of original TRANSFER version 1.0. It allows transfer of files between C-128 CP/M and MS-DOS disks. The four different types of MS-DOS disks can be used: single/double sided, 8/9 sectors per track. The enhancements made are: 1) The new version can be used with a single C-1571 drive. 2) It can format MS-DOS disks. 3) It allows you to view a text file directly from a MS-DOS disk. 4) It can rename a file on MS-DOS disk. Things to be aware of when using this program: 1) When C-128 displays a disk format selection at the bottom of the screen, use the right/left arrow keys to make this format match the type of MS-DOS disk in the drive. Valid choices are MSDOS-1 DS or MSDOS-1 SS (the 8 sector/track formats from older MSDOS versions), and MSDOS-2 DS or MSDOS-2 SS (the newer 9 sector/track formats). Do not choose IBM-8 DS or IBM-8 SS as these are not MSDOS formats. When the correct format is displayed, the return key should be pressed to continue with the program. 2) Always use scratch disk as a "messenger disk" to carry files between C-128 CP/M and a MS-DOS machine. Avoid allowing one disk to be written to by two different host systems, although it may seem harmless most of the time. 3) If you need to change disks, the best time to do it is when you see the main selection menu displayed on the screen. After changing disks (before starting a new File Transfer operation) it is suggested that you execute a dummy Directory operation just to log onto the new disk. Otherwise, you may get the TURBO PASCAL error message such as "I/O Error F0, Disk Write Error". This is equivalent to the familiar CP/M error message "BDOS Error, Read Only" caused by changing disks before writing to it. 4) While transferring many files by using a wildcard file designation, the key can be used, if desired, to abort the operation. 5) Be careful with Menu Selection 7 (Restore FAT on MS-DOS). Avoid using this option unless you are absolutely sure you know what you are doing. It can destroy your disk instantly. What it does is restoring FAT area number one using FAT area number two as the backup FAT. But it does not restore Directory area. (This program modifies FAT area number one only, and leaves the number two area untouched.) In case you need to use this option, the FAT Size in Sectors is 1 for MSDOS-1 DS and MSDOS-1 SS, and 2 for MSDOS-2 DS and MSDOS-2 SS. The present version (1.2C) employed techniques used by Frank Prindle in his C programs RDMS233C.C and UNIDRIVE.C, both of which were written to be run on C-128 with C-1571 drive. B-J Lee Nov 1987 [71171, 3260] ******************************************************************************  (* module 01 *) procedure Box(X1,Y1,X2,Y2: integer); var I: integer; begin gotoxy(X1,Y1); for I:= X1 to X2 do write('*'); for I:= Y1 to Y2 do begin gotoxy(X2,I); write('*'); end; gotoxy(X1,Y2); for I:= X2 downto X1 do write('*'); for I:= Y2 downto Y1 do begin gotoxy(X1,I); write('*'); end; end; function MainSelection: char; var Ch: char; begin ClrScr; Box(13,5,60,23); writeln('* TRANSFER - vers ',Vers,' - Commodore 128/1571 '); gotoxy(MenuMargin,8); write(' CP/M= ',chr(CPM_Drive+ord('A')),':'); write(' MS-DOS= ',chr(MS_DOS_Drive+ord('A')),':'); gotoxy(MenuMargin,10); write('1. Transfer File: CP/M ==> MS-DOS'); gotoxy(MenuMargin,11); write('2. Transfer File: CP/M <== MS-DOS'); gotoxy(MenuMargin,12); write('3. Directory of MS-DOS Disk'); gotoxy(MenuMargin,13); write('4. Allocation Map MS-DOS Disk'); gotoxy(MenuMargin,14); write('5. Directory of CP/M Disk'); gotoxy(MenuMargin,15); write('6. Erase File MS-DOS Disk'); gotoxy(MenuMargin,16); write('7. Restore FAT'); gotoxy(MenuMargin,17); write('8. Rename File MS-DOS Disk'); gotoxy(MenuMargin,18); write('9. Format Disk MS-DOS Disk'); gotoxy(MenuMargin,19); write('0. View Text File MS-DOS Disk'); repeat gotoxy(16,21); write(' Enter Your Selection ( to Quit): '); read(KBD,Ch); until (Ch in [#27, '0'..'9']); MainSelection:= Ch; end; procedure Continue; var Ch: char; begin write('Press [Return] to Continue..'); repeat read(KBD,Ch); if (Ch = #27) then Stop := true; until (Ch = #$D); end; procedure NextSector(var S: integer; var T: integer); begin S:= S + 1; if (S >= NSectors) then begin S:= MinSector; T:= T + 1; end; end; procedure DiskError; begin writeln; write('Disk I/O Error, '); Continue; end; procedure BiosSelect(DriveCode: integer; First: Boolean); begin if not ((Selection = '0') and (DriveCode = CPM_Drive)) then begin if (CPMversion >= $30) then bdos(LOGDSK, DriveCode); {added for safety} if First then D := bios3(SELDSK,0,DriveCode,0,0) else D := bios3(SELDSK,0,DriveCode,1,0); BiosError := (D = 0); if DEBUG then begin writeln; writeln('DriveCode=', DriveCode, ' DPH Address=', D); end; end; end; procedure ReadSector(Sector,Track,Address: integer); var Rec: integer; RPS: integer; I: integer; begin {if SingleSided then Track:= Track * 2;} RPS:= SectorSize div 128; if (CPMversion >= $30) then RPS := 1; BiosError:= False; for I:= 0 to (RPS -1)do begin D := bios3(SETTRK,0,track,0,0); (* select track *) if SecTrans then Rec:= bios3(SECTRAN,0,Sector * RPS + I + SO,0,0) (* translate sector *) else Rec:= (Sector * RPS + I + SO); D := bios3(SETSEC,0,Rec,0,0); (* select sector *) D := bios3(SETDMA,0,(I * 128) + Address,0,0);(* set dma addr *) BiosError:= (BiosError or (bios3(RDSEC,0,0,0,0)<>0)); (* read 128 bytes *) end; if BiosError then DiskError; end; procedure WriteSector(Sector,Track,Address: integer); var Rec: integer; RPS: integer; I: integer; begin {if SingleSided then Track:= Track * 2;} RPS:= SectorSize div 128; if (CPMversion >= $30) then RPS := 1; BiosError:= False; for I:= 0 to (RPS -1)do begin D := bios3(SETTRK,0,track,0,0); (* select track *) if SecTrans then Rec:= bios3(SECTRAN,0,Sector * RPS + I + SO,0,0) (* translate sector *) else Rec:= (Sector * RPS + I + SO); D := bios3(SETSEC,0,Rec,0,0); (* select sector *) D := bios3(SETDMA,0,(I * 128) + Address,0,0);(* set dma addr *) BiosError:= (BiosError or (bios3(WRSEC,0,0,0,0)<>0)); (* write 128 bytes *) end; if BiosError then DiskError; end; procedure GetFAT; begin ReadSector(FirstFATSector,0,addr(FAT)); ReadSector(FirstFATSector + 1,0,addr(FAT)+SectorSize); end; procedure PutFAT; var S,T,I: integer; begin S:= FirstFATSector; T:= 0; for I:= 0 to FATSize-1 do begin WriteSector(S,T,addr(FAT) + (SectorSize * I)); NextSector(S,T); end; end; procedure ReadCluster(Cl, BufferIndex: integer); var I: integer; Sector: integer; Track: integer; begin Cl:= Cl - 2; Track:= (Cl * SecsPerCluster) div NSectors; Sector:= (Cl * SecsPerCluster) mod NSectors; Sector:= Sector + FirstDataSector; Track:= Track + FirstDataTrack + (Sector div NSectors); Sector:= Sector mod NSectors; for I:= 0 to (SecsPerCluster -1) do begin ReadSector(Sector,Track,addr( DataBuffer[ I * SectorSize + BufferIndex] )); NextSector(Sector,Track); end; end; procedure WriteCluster(Cl, BufferIndex: integer); var I: integer; Sector: integer; Track: integer; begin Cl:= Cl - 2; Track:= (Cl * SecsPerCluster) div NSectors; Sector:= (Cl * SecsPerCluster) mod NSectors; Sector:= Sector + FirstDataSector; Track:= Track + FirstDataTrack + (Sector div NSectors); Sector:= Sector mod NSectors; for I:= 0 to (SecsPerCluster -1) do begin WriteSector(Sector,Track,addr( DataBuffer[ I * SectorSize + BufferIndex] )); NextSector(Sector,Track); end; end; function FATPointer(Index: integer): Integer; (* 2..NClusters + 2 *) var Result,I: Integer; OddNum: Boolean; begin I:= ((Index * 3) div 2) +1; Result:= (FAT[I] + (256 * FAT[I + 1])); if odd(Index) then Result:= Result shr 4; FATPointer:= (Result and $FFF); end; function Break: boolean; var Ch: char; begin if KeyPressed then begin read(KBD,Ch); if (Ch = ^S) then begin while not KeyPressed do; read(KBD,Ch); end; if (Ch = #27) then Break:= true else Break:= false; end else Break:= false; end; (* end module 01 *)  procedure ConvertName(Str: Str20; var N: NameAry; var T: TypeAry); var I,J: integer; begin for I:= 1 to NameSize do N[I]:= ' '; for I:= 1 to TypeSize do T[I]:= ' '; if (Str = '') then Str:= '*.*'; if (pos('.',Str) = 0) then Str:= concat(Str,'.'); if not (pos('.',Str)-1 > NameSize) then for I:= 1 to pos('.',Str)-1 do N[I]:= upcase(Str[I]); if not (length(copy(Str,pos('.',Str)+1,20)) > TypeSize) then for I:= pos('.',Str)+1 to length(Str) do T[I-pos('.',Str)]:= upcase(Str[I]); for I:= 1 to NameSize do if (N[I] = '*') then for J:= I to NameSize do N[J]:= '?'; for I:= 1 to TypeSize do if (T[I] = '*') then for J:= I to TypeSize do T[J]:= '?'; end; function SameName(S: Str20; FN: NameAry; FT: TypeAry): boolean; var N: NameAry; T: TypeAry; I,J: integer; Match: boolean; begin ConvertName(S,N,T); Match:= true; for I:= 1 to NameSize do if ((N[I] <> FN[I]) and (N[I] <> '?')) then Match:= False; for I:= 1 to TypeSize do if ((T[I] <> FT[I]) and (T[I] <> '?')) then Match:= False; SameName:= Match; end; procedure SearchNextAll(FileName: Str20; var Error: integer); var I,FCBsPerSector: integer; begin repeat Error:= FoundDir; { default } FCBsPerSector:= (SectorSize div SizePC_FCB); if ((DirOffset mod FCBsPerSector) = 0) then begin DirOffset:= 0; NextSector(DirSector,DirTrack); ReadSector(DirSector,DirTrack,Addr(DirBuffer)); DirSectorCount:= DirSectorCount +1; end; if (DirSectorCount < DirSecs) then begin DOS_FCB:= ptr(addr(DirBuffer) + (DirOffset * SizePC_FCB)); if (Selection <> '3') and DEBUG then begin if (DirOffset = 0) then writeln; for I := 1 to 8 do write(ord(DOS_FCB^.Name[I]), ' '); writeln(' ', DOS_FCB^.Attribute, ' ', DOS_FCB^.ClusterNo); end; if (DOS_FCB^.Name[1] in [#0,#$F6,#$E5]) then Error:= MTDirectory; end else Error:= EODirectory; DirOffset:= DirOffset +1; until ((Error = EODirectory) or (Error = MTDirectory) or (SameName(FileName,DOS_FCB^.Name,DOS_FCB^.Extention))); If (Error = EODirectory) Then Begin VolumeName:= False; SubDirName:= False; End Else Begin VolumeName:= (DOS_FCB^.Attribute and $08) <> 0; SubDirName:= (DOS_FCB^.Attribute and $10) <> 0; VolumeName := VolumeName and (DOS_FCB^.Name[1] <> #0); {for IBM-PC clones} SubDirName := SubDirName and (DOS_FCB^.Name[1] <> #0); End end; procedure SearchNext(FN: Str20; var Err: integer); begin repeat SearchNextAll(FN,Err); if (DOS_FCB^.Name[1] = #0) then { "high water" mark } Err:= EODirectory; until ((Err = EODirectory) or (Err = FoundDir)); end; procedure SearchFirstAll( FileName: Str20; var Error: integer ); var I: integer; begin DirOffset:= 0; DirTrack:= 0; DirSectorCount:= -1; DirSector:= FirstDirSector -1; SearchNextAll(FileName,Error); end; procedure SearchFirst(FN: Str20; var Err: integer); begin SearchFirstAll(FN,Err); if (Err = MTDirectory) then SearchNext(FN,Err); end; procedure IdentifyMS_DOS; begin BiosSelect(MS_DOS_Drive, First); SectorSize:= 512; RecordsPerSector:= SectorSize div 128; FirstFATSector:= 1; GetFAT; case FAT[1] of $FF: begin Identity:= ds8spt; (* MSDOS-1 DS *) FATSize:= 1; (* size of FAT in sectors (1 copy)*) DirSecs:= 7; (* number of sectors in directory *) NTracks:= 80; (* number of tracks on disk *) NSectors:= 8; (* number of sectors per track *) SecsPerCluster:= 2; (* number of sectors per cluster *) SingleSided:= false; end; $FE: begin Identity:= ss8spt; (* MSDOS-1 SS *) FATSize:= 1; DirSecs:= 4; NTracks:= 40; NSectors:= 8; SecsPerCluster:= 1; SingleSided:= true; end; $FD: begin Identity:= ds9spt; (* MSDOS-2 DS *) FATSize:= 2; DirSecs:= 7; NTracks:= 80; NSectors:= 9; SecsPerCluster:= 2; SingleSided:= false; end; $FC: begin Identity:= ss9spt; (* MSDOS-2 SS *) FATSize:= 2; DirSecs:= 4; NTracks:= 40; NSectors:= 9; SecsPerCluster:= 1; { should be 1, instead of 2 } SingleSided:= true; end; else begin (* Try Another Sector Size *) SectorSize:= 256; FirstFATSector:= 2; RecordsPerSector:= SectorSize div 128; GetFAT; Case FAT[1] of $F8: Begin Identity:= B_20; (* Burroughs B-20 *) FATSize:= 2; DirSecs:= 18; NTracks:= 160; NSectors:= 16; SecsPerCluster:= 8; SingleSided:= false; End; else Begin Identity:= Unidentified; gotoxy(1,23); write('Cannot Identify MS-DOS Disk, '); Continue; end; (* else Case *) end; (* Case *) end; (* else Case *) end; (* Case *) if not (Identity = Unidentified) then begin FirstDirSector:= FatSize * 2 + FirstFATSector; FirstDataSector:= (FirstDirSector + DirSecs) mod NSectors; FirstDataTrack:= (FirstDirSector + DirSecs) div NSectors; NClusters:= (NTracks * NSectors div SecsPerCluster) - (((FATSize * 2) + DirSecs + 1) div SecsPerCluster); end; end; procedure RestoreFAT; var Ch: char; S,T,I: integer; begin BiosSelect(MS_DOS_Drive, First); writeln('WARNING: Your disk can be distroyed!'); writeln; write('FAT Size in Sectors (1 or 2, to abort): '); repeat read(KBD, Ch); until (Ch in [#13, '1', '2']); writeln(Ch); if (Ch = #13) then exit; FATSize := ord(Ch) - 48; S:= 1 + FATSize; T:= 0; for I:= 0 to FATSize-1 do begin ReadSector(S,T,addr(FAT) + (SectorSize * I)); NextSector(S,T); end; PutFAT; Continue; end;  (* module 3 *) procedure SearchFileCPM( FileName: Str20; var Error: integer; First: boolean ); var I,J: integer; begin BDos(SetDMAF,addr(CPM_Buf)); ConvertName(FileName,CPM_FCB.Name,CPM_FCB.Extention); CPM_FCB.DriveCode:= CPM_Drive + 1; CPM_FCB.Extent:= 0; CPM_FCB.CR:= 0; if First then I:= BDos(SearchF,addr(CPM_FCB)) else I:= BDos(SearchN,addr(CPM_FCB)); if (I = $FF) then Error:= EODirectory else begin Error:= 0; I:= (((I and 3) * SizeCPM_FCB) + 1); for J:= 0 to (NameSize + TypeSize) do mem[addr( CPM_FCB ) + J]:= mem[ addr( CPM_Buf[I]) + J]; end; end; procedure DirCPM; var ErrorCode, Count, I,N: integer; FileName: Str20; begin BiosSelect(CPM_Drive, First); Count:= 0; ClrScr; writeln; write('Dir Mask: '); readln(FileName); writeln; SearchFileCPM(FileName,ErrorCode,First); if (ErrorCode = EODirectory) then begin write('No File, '); Continue; end else begin repeat if ((Count mod 4) = 0) then writeln else write(' : '); write(CPM_DriveCh,':'); for I:= 1 to NameSize do write(CPM_FCB.Name[I]); write('.'); for I:= 1 to TypeSize do write(CPM_FCB.Extention[I]); Count:= Count + 1; SearchFileCPM(FileName,ErrorCode,Next); until (ErrorCode = EODirectory) or Break; writeln; writeln; writeln('File Count: ',Count); Continue; end; end; (* end module 3 *)  procedure SetFATPointer(Loc,Val: integer); var I,R: integer; begin I:= ((Loc * 3) div 2) +1; R:= (FAT[I] or (FAT[I+1] shl 8)); if odd(loc) then R:= ((R and $F) or (Val shl 4)) else R:= ((R and $F000) or (Val and $FFF)); FAT[I]:= (R and $FF); FAT[I+1]:= ((R shr 8) and $FF); end; procedure WriteMS_DOS; var FileName: Str20; UnAmbiguous: Str20; ErrorCode: integer; I: integer; RecsPerCluster: integer; Remaining: integer; NRecs: integer; FAT_Marker: integer; LastMarker: integer; procedure Get_Unambiguous; begin UnAmbiguous:= ''; for I:= 1 to NameSize do if not (CPM_FCB.Name[I] = ' ') then UnAmbiguous:= UnAmbiguous + CPM_FCB.Name[I]; UnAmbiguous:= UnAmbiguous + '.'; for I:= 1 to TypeSize do if not (CPM_FCB.Extention = ' ') then UnAmbiguous:= UnAmbiguous + CPM_FCB.Extention[I]; end; function FirstFree(Start: integer): integer; var I: integer; begin I:= Start; while (I < NClusters + 2) and (FATPointer(I) <> 0) do I:= I + 1; FirstFree:= I; if (I = NClusters + 2) then BiosError:= true; end; procedure ReadCPMfileIntoBuffer; begin if (Remaining > DataBufferSize div 128) then NRecs:= DataBufferSize div 128 else NRecs:= Remaining; fillchar(DataBuffer, DataBufferSize, 0); BlockRead(InFile, DataBuffer[1], NRecs); if DEBUG then writeln('NRecs=', NRecs); end; procedure WriteMS_DOSfileFromBuffer; begin NumberOfClusters := NRecs div RecsPerCluster; if ((NRecs mod RecsPerCluster) > 0) then NumberOfClusters := NumberOfClusters + 1; for I := 0 to NumberOfClusters - 1 do begin SetFATPointer(FAT_Marker,FirstFree(FAT_Marker + 1)); WriteCluster(FAT_Marker, I * RecsPerCluster * 128 + 1); LastMarker:= FAT_Marker; FAT_Marker:= FirstFree(FAT_Marker + 1); end; end; procedure ReWriteMS_DOS(FN: NameAry; FT: TypeAry); {Open a new MS_DOS file} var ErrorCode: integer; S: Str20; begin S:= '????????.???'; VolumeName:= False; SubDirName:= False; SearchFirstAll(S,ErrorCode); while (ErrorCode <> MTDirectory) and (ErrorCode <> EODirectory) or VolumeName or SubDirName do SearchNextAll(S,ErrorCode); if (ErrorCode = EODirectory) then BiosError:= true else begin DOS_FCB^.Name:= FN; DOS_FCB^.Extention:= FT; DOS_FCB^.Attribute:= $20; {changed from 0: for IBM-PC Clones} for I:= 12 to 21 do DOS_FCB^.Rsrvd[I]:= 0; DOS_FCB^.Time:= 0; DOS_FCB^.Date:= 0; FAT_Marker:= FirstFree(2); DOS_FCB^.ClusterNo:= FAT_Marker; end; end; procedure CloseMS_DOS(Size: integer); {Update Directory and FAT sectors} { Size is filesize / 128 } var Size2: integer; begin Size2:= hi(Size shr 1); { prevent overflow } Size:= ((Size and $1FF) shl 7); DOS_FCB^.FileSize[1]:= lo(Size); DOS_FCB^.FileSize[2]:= hi(Size); DOS_FCB^.FileSize[3]:= lo(Size2); DOS_FCB^.FileSize[4]:= hi(Size2); if (Size = 0) then (* DOS_FCB^.Cluster:= $FFF *) else SetFATPointer(LastMarker,$FFF); WriteSector(DirSector,DirTrack,addr(DirBuffer)); PutFAT; end; begin (* WriteMS_DOS *) {bdos(RESETDSK);} {for safety} repeat ClrScr; writeln; writeln('File Transfer From CP/M to MS-DOS'); writeln; write('File Name to Get From CP/M: '); readln(Filename); writeln; Stop:= (pos(':',FileName) <> 0); if Stop then begin write('DriveCode = ',CPM_DriveCh); writeln(', Do Not Include In Name.'); Continue; end; until not Stop; Stop:= false; CheckWildcard(FileName); BiosSelect(CPM_Drive, First); SearchFileCPM(FileName,ErrorCode,First); if (ErrorCode = EODirectory) then write('File Not Found, ') else begin Get_Unambiguous; assign(InFile,UnAmbiguous); reset(InFile); Remaining := FileSize(InFile); if DEBUG then writeln('FileSize=', Remaining); ReadCPMfileIntoBuffer; IdentifyMS_DOS; if (Identity = Unidentified) then begin BiosSelect(CPM_Drive, Next); close(InFile); end else begin write('Transfering -'); RecsPerCluster:= RecordsPerSector * SecsPerCluster; repeat SearchFirst(Unambiguous,ErrorCode); writeln; write(CPM_DriveCh + ':',UnAmbiguous); if (ErrorCode = FoundDir) then begin write(' Exists'); Stop := true; end else begin ReWriteMS_DOS(CPM_FCB.Name,CPM_FCB.Extention); if DEBUG then writeln; Stop := Stop or Break; if not BiosError and not Stop then begin WriteMS_DOSfileFromBuffer; Stop := Stop or BiosError or Break; Remaining := Remaining - NRecs; while (Remaining > 0) and not Stop do begin BiosSelect(CPM_Drive, Next); ReadCPMfileIntoBuffer; BiosSelect(MS_DOS_Drive, Next); WriteMS_DOSfileFromBuffer; Stop:= BiosError or Stop or Break; Remaining:= Remaining - NRecs; end; (* while *) if not Stop then CloseMS_DOS(FileSize(InFile)); end; (* if not bioserror *) end; (* if founddir *) BiosSelect(CPM_Drive,Next); close(InFile); Stop := Stop or Break; if BiosError then begin Stop:= true; writeln; writeln('MS-DOS Write Error or Disk or Directory Full'); end else if WildCard and not Stop then begin SearchFileCPM(UnAmbiguous,ErrorCode,First); SearchFileCPM(FileName,ErrorCode,Next); if (ErrorCode = FoundDir) then begin Get_Unambiguous; assign(InFile,UnAmbiguous); reset(InFile); Remaining := FileSize(InFile); if DEBUG then writeln('FileSize=', Remaining); ReadCPMfileIntoBuffer; BiosSelect(MS_DOS_Drive,Next); end; end; until (ErrorCode = EODirectory) or Stop or not WildCard; writeln; writeln; end; (* if not Identity *) end; (* if EODirectory *) if Stop then write('Aborted, '); Continue; end; (* WriteMS_DOS *)  procedure Set_FileLengthCPM; begin CPM_FCB.DriveCode := CPM_Drive + 1; move(DOS_FCB^.Name, CPM_FCB.Name, 8); move(DOS_FCB^.Extention, CPM_FCB.Extention, 3); I := ord(CPM_FCB.Name[6]); I := I or $80; {set high bit f6'} CPM_FCB.Name[6] := chr(I); for I := 0 to 19 do mem[addr(CPM_FCB.Extent) + I] := 0; CPM_FCB.CR := 128 - (DOS_FCB^.FileSize[1] and $7F); bdos(SETATT, addr(CPM_FCB)); end; function NumberOfRecords(Index: integer): integer; var I: integer; begin I := (Index - 1) div 128; if (((Index - 1) mod 128) > 0) then I := I + 1; NumberOfRecords := I; end; Function SizeDOS_File(Var A: SizeArray): Real; Begin SizeDOS_File:= (A[1] + (256.0 * A[2]) + (256.0 * 256.0 * A[3]) + (256.0 * 256.0 * 256.0 * A[4])); End; procedure BufferToScreen; var I, J: integer; begin I := 1; while (I < BufferIndex) and not Stop do begin J := ord(DataBuffer[I]); if (J = $0A) or (J = $0D) or ((J > $1F) and (J < $80)) then write(DataBuffer[I]); Stop := Stop or Break; I := I + 1; end; end; procedure ReadMS_DOS; var FileName: Str20; CPMName: Str20; I,Err: integer; Cl: integer; RecordsPerCluster: integer; Size: Real; procedure AdvanceDataBufferIndex; begin if (NumberOfClusters > 0) then begin NumberOfClusters := NumberOfClusters - 1; BufferIndex := BufferIndex + RecordsPerCluster * 128; end else BufferIndex := BufferIndex + ExtraBytes; end; begin (* ReadMS_DOS *) {bdos(RESETDSK);} {for safety} IdentifyMS_DOS; if not (Identity = Unidentified) then begin ClrScr; writeln; if (Selection = '2') then writeln('File Transfer From MS-DOS to CP/M') else writeln('View a Text File on MS_DOS Disk'); writeln; write('File Name to Get From MS-DOS: '); readln(FileName); writeln; Stop:= false; CheckWildcard(FileName); SearchFirst(FileName,Err); While VolumeName or SubDirName do SearchNext(FileName,Err); if (Err = EODirectory) then begin write('File Not Found, '); end else begin writeln('Transfering -'); RecordsPerCluster:= RecordsPerSector * SecsPerCluster; BiosSelect(CPM_Drive, First); repeat CPMName:= ''; for I:= 1 to NameSize do if not (DOS_FCB^.Name[I]=' ') then CPMName:= CPMName + DOS_FCB^.Name[I]; CPMName:= CPMName + '.'; for I:= 1 to TypeSize do CPMName:= CPMName + DOS_FCB^.Extention[I]; if (Selection = '2') then CPMName:= concat(CPM_DriveCh,':',CPMName); writeln(CPMName); if (Selection = '2') then begin assign(CPMFile,CPMName); rewrite(CPMFile); end else begin writeln; writeln('Press to pause, to abort -'); writeln; end; Stop := Stop or Break; if not Stop then begin Cl:= DOS_FCB^.ClusterNo; Size:= SizeDOS_File(DOS_FCB^.FileSize); NumberOfClusters := Trunc(Size / (RecordsPerCluster * 128.0)); ExtraBytes := Trunc(Size - (NumberOfClusters * RecordsPerCluster * 128.0)); fillchar(DataBuffer, DataBufferSize, 0); BufferIndex := 1; BiosSelect(MS_DOS_Drive, Next); while (Cl < $FF8) and not Stop do begin ReadCluster(Cl, BufferIndex); AdvanceDataBufferIndex; if ((BufferIndex-1)>DataBufferSize-(RecordsPerCluster*128)) then begin BiosSelect(CPM_Drive, Next); if (Selection = '2') then blockwrite(CPMFile,DataBuffer[1],NumberOfRecords(BufferIndex)) else BufferToScreen; BiosSelect(MS_DOS_Drive, Next); fillchar(DataBuffer, DataBufferSize, 0); BufferIndex := 1; end; Cl:= FATPointer(Cl); (* Point to Next Cluster *) end; BiosSelect(CPM_Drive, Next); DataBuffer[BufferIndex] := ^Z; if (Selection = '2') then begin blockwrite(CPMFile, DataBuffer[1], NumberOfRecords(BufferIndex)); close(CPMFile); if (CPMversion > $30) then Set_FileLengthCPM; end else if not Stop then BufferToScreen; end; (* if not Stop *) Stop := Stop or Break; if Wildcard and not Stop then begin BiosSelect(MS_DOS_Drive, Next); Repeat SearchNext(FileName,Err); Until Not (VolumeName or SubDirName); if not (Err = EODirectory) then BiosSelect(CPM_Drive, Next); end; until (Err = EODirectory) or Stop or not Wildcard; writeln; writeln; end; (* if EODirectory *) if Stop then write('Aborted, '); Continue; end; end; procedure DirMS_DOS; var ErrorCode, Count, I,N: integer; X: real; FileName: Str20; MonthString: array[0..38] of char; begin MonthString:= '...JanFebMarAprMayJunJulAugSepOctNovDec'; Count:= 0; IdentifyMS_DOS; if not (Identity = Unidentified) then begin ClrScr; writeln; write('Dir Mask: '); readln(FileName); writeln; writeln('Name', 'Attrubutes':18, 'Clstr':7, 'Date':13, 'Time':10, 'Size':8); for I:= 1 to 60 do write('-'); SearchFirst(FileName,ErrorCode); repeat if (ErrorCode = FoundDir) then begin writeln; Count:= Count + 1; with DOS_FCB^ do begin for I:= 1 to NameSize do write(Name[I]); write('.'); for I:= 1 to TypeSize do write(Extention[I]); write(' '); N:= Attribute; If VolumeName Then Write('') Else if SubDirName Then Write('') Else for I:= 1 to 8 do begin write(chr(((N shr 7) and 1) + $30)); N:= N shl 1; end; write(ClusterNo:7); write(' '); N:= ((Date shr 5) and $F); if (N > 12) then N:= 0; N:= N * 3; for I:= N to N+2 do write(MonthString[I]); write(' '); N:= Date and $1F; if N < 10 then write('0'); write(N); write(',',(Date shr 9) + 1980); write(' '); N:= (Time shr 11); if N < 10 then write('0'); write(N,':'); N:= ((Time shr 5) and 63); if N < 10 then write('0'); write(N,':'); N:= ((Time and $1F) * 2); if N < 10 then write('0'); write(N); write(' ',SizeDOS_File(FileSize):6:0); end; end; SearchNext(FileName,ErrorCode); until (ErrorCode = EODirectory) or Break; writeln; writeln; writeln('File Count: ',Count); Continue; end; end; procedure MapMS_DOS; begin IdentifyMS_DOS; if not (Identity = Unidentified) then begin ClrScr; for I:= 0 to NClusters -1 do begin if (I mod 18) = 0 then writeln; write(FATPointer(I + 2),',') end; writeln; writeln; continue; end; end;  procedure FormatMS_DOS; {type str40 = string[40];} var Ch: char; I: integer; FormatNumber: integer; {function Yes(Message: str40): boolean; begin write(Message, 'Y or N? '); readln(Ch); if (upcase(Ch) = 'Y') then Yes := true else Yes := false; end;} type User0Command = record {8502 BIOS function 4, Subfunction 8: } Command: byte; { Format a diskette } Par4: byte; Par5: byte; Par6: byte; Par7: byte; Par8: byte; Par9: byte; Par10: byte; Par11: byte; end; const FormatCommand: array[0..3] of User0Command = ((Command:38; Par4:129; Par5:0; Par6:2; Par7:39; {MSDOS-1 DS} Par8:8; Par9:0; Par10:0; Par11:0), (Command:6; Par4:129; Par5:0; Par6:2; Par7:39; {MSDOS-1 SS} Par8:8; Par9:0; Par10:0; Par11:0), (Command:38; Par4:129; Par5:0; Par6:2; Par7:39; {MSDOS-2 DS} Par8:9; Par9:0; Par10:0; Par11:0), (Command:6; Par4:129; Par5:0; Par6:2; Par7:39; {MSDOS-2 SS} Par8:9; Par9:0; Par10:0; Par11:0)); procedure LoadFormatCommand(EntryIndex: integer); var I: integer; begin mem[$FD02] := 1; {DRIVE#: device 8, drive 0} mem[$FD08] := 1; {FAST set} mem[$FE00] := 9; {@BUFFER: set to command length} for I := 0 to 8 do mem[$FE01 + I] := mem[addr(FormatCommand[EntryIndex]) + I]; end; begin (* FormatMS_DOS *) if (bdos(CURDSK) <> 0) then begin writeln('Formatting MS-DOS disks will be done in Drive A.'); writeln('Insert a scratch CP/M disk in Drive A first, just to log onto it'); writeln('before proceeding with a blank disk to be formatted.'); BiosSelect(0, First); end; writeln; writeln('Enter the type of disk to be formatted:'); writeln; writeln(' 1 : MSDOS-1 DS (8 sec/trk)'); writeln; writeln(' 2 : MSDOS-1 SS (8 sec/trk)'); writeln; writeln(' 3 : MSDOS-2 DS (9 sec/trk)'); writeln; writeln(' 4 : MSDOS-2 SS (9 sec/trk)'); writeln; writeln; write('Which one (1 - 4)? '); repeat read(KBD, Ch); until (Ch in ['1'..'4']); writeln(Ch); FormatNumber := ord(Ch) - 49; FAT[1] := not FormatNumber; {Disk Type Byte} Stop := false; writeln; writeln(' *** Insert a blank disk to be formatted in drive A now ***'); write('Type $ to begin formatting. '); repeat read(KBD, Ch); until (Ch = '$'); writeln(Ch); LoadFormatCommand(FormatNumber); {8502 BIOS User function 4, Subfunction 8:} D := bios3(USERFUN, 4, 0, 0, 8); { format a disk } Stop := (mem[$FD06] <> 0); {VICDATA: Disk error status} if Stop then writeln('Error Formatting') else begin BiosSelect(0, First); {initiallize drive for disk write} fillchar(Buffer, 512, 0); Buffer[1] := chr(FAT[1]); FirstFATSector := 1; FATSize := (FormatNumber div 2) + 1; WriteSector(FirstFATSector, 0, addr(Buffer)); WriteSector(FirstFATSector + FATSize, 0, addr(Buffer)); writeln; if not BiosError then writeln('Formatting complete'); end; Continue; bdos(RESETDSK); {bdos(LOGDSK, CPM_Drive);} end;