MS-WASH PAS^BMSCOPY COMVMSCOPY PAS`MSDISK INC|:MSREAD CHN RoMSREAD PAS"wMSWRITE CHN_`MSWRITE INCWYMSWRITE PASl Program MSCOPY ; { Version 1.1 01. Februar 92 (c) Copyright by Andreas Buchelt Anpassung an andere CP/M plus Systeme : ======================================= MSCOPY besteht aus den Teilen MSCOPY.COM, MSREAD.CHN und MSWRITE.CHN, die sich alle auf dem gleichen Laufwerk befinden. Der Zugriff auf die DOS-Dis- ketten erfolgt ueber CPM+ indirekte BIOS-Calls. Multi-IO wird unterstuetzt, soweit im BIOS implementiert. Aenderungen sind nur notwendig, wenn das BIOS nicht ueber Sektor-Wrap auf die 2. Seite umschalten kann. Der DPB muss fuer das DOS-Laufwerk vor dem Programmstart folgende Form haben: DW 72 ; 72 128-Byte Records /Track DB 4 ; 2 KByte CP/M-Blockgroesse DB 15 ; Blockmask DB 1 ; 1 Extent (32K / Dir) DW 179 ; 180 Blocks = 360 K DW 0 ; keine Dirs !!! DB 0 ; keine Dir-Bloaecke DB 0 ; DW 8000 ; fixed Media, keine Dirs checken DW 0 ; keine Systracks DB 2 ; Sektorlaenge 512 Byte DB 3 ; Sektor Maske Dieses Programm darf mit Source weitergegeben werden, aber bitte die Copyright-Vermerke n i c h t entfernen !!! Sollten noch Fehler gefunden werden, so bin ich fuer Hinweise dankbar. Andreas Buchelt Am Muehlbach 17 D 8046 Garching Hinweise : Erarbeitet und getestet mit TURBO-Pascal 3.00 unter CP/M plus ========== mit einer RAM-Floppy ! Compiliert zu COM-File in 3,0 s ! MSCOPY.COM compiliert mit Endadresse 0D700H . Anzahl der DOS- Sektor-Puffer kann der Speichergroesse angepasst werden. ==============================================================================} {$imsdisk.inc} var chainfile : file ; begin MSDrive := 3 ; { Standard DOS-LW = D: systemabgengig !! } while true do begin clrscr ; gotoxy(18,5) ; write('MS-DOS Disketten unter CPM-plus lesen und schreiben') ; gotoxy(18,6) ; write('===================================================') ; gotoxy(10,10) ; write('MS-DOS Diskette in Laufwerk ',chr(MSDrive+65),': einlegen.') ; gotoxy(8,12) ; write('Disk-Parameter-Block fuer Laufwerk ',chr(MSDrive+65),': muss ') ; write('korrekt gesetzt sein.') ; gotoxy(8,13); write('Seitenumschaltung erfolgt ueber Sektorueberlauf !') ; gotoxy(10,15) ; write('Lesen MS-Disk ') ; gotoxy(10,16) ; write('Schreiben MS-Disk ') ; gotoxy(10,17) ; write('DOS-Laufwerk wechseln ') ; gotoxy(10,18) ; write('Exit --->') ; repeat read(kbd,c) ; c := upcase(c) ; until (c = 'R') or (c = 'W') or (c = 'X') or (c = 'C') ; case c of 'R' : begin Assign(chainfile,'MSREAD.CHN') ; Chain(chainfile) ; end ; 'W' : begin Assign(chainfile,'MSWRITE.CHN') ; Chain(chainfile) ; end ; 'C' : begin gotoxy(8,22) ; write('Enter new DOS-Drive : ') ; readln(c) ; c := upcase(c) ; MSDrive := ord(c) - 65 ; CurDrv := BDos(25) ; { Rette aktuelles LW } destlw := chr(CurDrv + 65 ) ; dummy := BDos(14,MSDrive) ; { existiert MSDOS-LW ? } BDos(14,CurDrv) ; if dummy <> 0 then begin meldung('MS-DOS-Laufwerk existiert nicht !? ') ; halt ; end ; end ; 'X' : halt ; end ; end ; end. {$r-} Program Lies_MS_Dos_Disketten; {============================================================================= Entwickelt auf Commodore PC 128 unter CP/M+ mit einem Diskettenlaufwerk Commodore 1571 nach MC TEDAS ----- Ueberarbeitet, Fehler entfernt, erweitert und umgebaut auf interaktives Utility von Andreas Buchelt Vers. 1.2 verarbeitet jetzt bis zu 256 Eintraege in einem Sub-Dir. Vers. 1.3 ScanDirectory unterscheidet zwischen Root und Subdirectory. Vers. 1.4 Wechsel zu MSWRITE ueber CHAIN . Vers. 1.5 nur noch fuer 360K-Disketten bzw. kein Patch des DPB mehr RW-Operationen mit Multi-IO-Unterstuetzung nur noch physikalische Sektoren werden verwendet Kommandos an ZCPR Z-FILER angeglichen Version 1.5 01. Februar 92 (c) Copyright by Andreas Buchelt Anpassung an andere CP/M plus Systeme : ======================================= Dieses Programm darf mit Source weitergegeben werden, aber bitte die Copyright-Vermerke n i c h t entfernen !!! Sollten noch Fehler gefunden werden, so bin ich fuer Hinweise dankbar. Andreas Buchelt Am Muehlbach 17 D 8046 Garching Hinweise : Erarbeitet und getestet mit TURBO-Pascal 3.00 unter CP/M plus ========== mit einer RAM-Floppy ! Compiliert zu CHN-File in 13,0 s ! MSREAD.CHN compiliert mit Endadresse 0D700H . Anzahl der DOS- Sektor-Puffer kann der Speichergroesse angepasst werden. ==============================================================================} {$imsdisk.inc} {-----------------------------------------------------------------------------} CONST { max 10 Sub-Dirs bei 80 Zeichen/Zeilex } { bei 90 oder 96 Zeichen/Zeile : MSD = 12} MSD = 12 ; { max. 12 Sub-Dirs in einem Directory !!!} Maxdir = 255 ; { max. 256 Dir-Eintraege bei DOS } dircol = 6 ; { 5 Sub-Dirspalten bei 80 Zeichen/Zeile } dirline = 24 ; { 23 bei 24 Zeilen/Schirm } var Entry : Array[0..Maxdir] of String[32] ; selected : Array[0..Maxdir] of Boolean ; Name_of_Disk : String14 ; SDir : Array[1..MSD] of String[32] ; f : real ; FreeSek : Array[1..3] of Byte ; Temp : String[32] ; fs,NSecs : Integer ; {Offset Fileende im Cluster} SubDirs : integer ; {-----------------------------------------------------------------------------} Function Filename(n : integer) : String14 ; begin Filename := copy(Entry[n],1,8)+'.'+copy(Entry[n],9,3) ; end ; {-----------------------------------------------------------------------------} Procedure Diskinfo ; begin Meldung('360K MS-DOS Diskette '); write(Disk_Space,' KByte frei') ; Wait(300) ; Meldung(' ') ; end ; {-----------------------------------------------------------------------------} procedure Titel ; begin gotoxy(10,1) ; writeln('*** Ingenious Systems MS-DOS ---> CP/M Copy Utility *** '); gotoxy(10,2) ; writeln(' from Andreas Buchelt Copyright (c) 1987'); end ; {-----------------------------------------------------------------------------} procedure Rahmen ; begin gotoxy(1,3) ; write(' Name der MS-DOS Diskette :',Name_of_Disk:12) ; write(' Angezeigtes Directory :',ActDir : 12) ; gotoxy(1,5) ; ClrEol ; gotoxy(22,5) ; write(' fuer Hilfe fuer Exit') ; gotoxy(1,dirline-2) ; ClrEol ; gotoxy(1,dirline-1) ; ClrEol ; gotoxy(1,dirline) ; ClrEol ; write('SubDirs : '); for i:= 0 to pred(SubDirs) do begin gotoxy(12 + 13 * abs(i mod dircol),dirline + i div dircol) ; write(Sdir[succ(i)]) ; end ; end ; {-----------------------------------------------------------------------------} procedure Display_Dir ; var i : integer ; begin if Anzahl < maxanz then Anzeig := Anzahl else Anzeig := maxanz-1 ; i := 0 ; while (i <= Anzeig) and ( i+r-1 < Anzahl) do begin gotoxy(2+(i div maxzeil) shl 4,7+i mod maxzeil) ; Entry[i][0] := chr(11) ; write(copy(Entry[i+r],1,8),'.',copy(Entry[i+r],9,3),' ') ; if selected[i+r] then write('#') else write(':') ; i := succ(i) ; end ; if maxanz-1 > Anzahl-r then begin gotoxy(2+(i div maxzeil) shl 4,7+i mod maxzeil) ; write('--------------') ; i := succ(i) ; while i mod maxzeil <> 0 do begin gotoxy(2+(i div maxzeil) shl 4,7+i mod maxzeil) ; write(' ') ; i := succ(i) ; end ; end ; end ; {-----------------------------------------------------------------------------} procedure Display( weiter : integer ) ; procedure mark( switch : boolean ) ; begin gotoxy(1+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; if switch then write('>') else write(' ') ; gotoxy(16+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; if switch then write('<') else write(' ') ; end ; begin Mark(false) ; dirsel := dirsel + weiter ; if anzahl < 0 then begin Meldung('Keine Datei in diesem Verzeichnis') ; Wait(300) ; Meldung(' ') ; exit ; end ; if dirsel < 0 then begin dirsel := 0 ; if (Anzahl > maxanz-1) and (r > 0) then begin dirsel := maxzeil ; r := r - maxzeil ; Display_Dir ; end ; end ; if dirsel > Anzahl then begin dirsel := 0 ; r := 0 ; end ; if r+dirsel > Anzahl then begin dirsel := 0 ; r := 0 ; Display_Dir ; end ; if dirsel > anzeig then begin r := r + maxzeil ; dirsel := maxanz - maxzeil ; Display_Dir ; end ; mark(true) ; end ; {-----------------------------------------------------------------------------} procedure Help ; begin for i:= 3 to 24 do begin gotoxy(1,i) ; ClrEol ; end ; gotoxy(20,5) ; write(' Befehlsverzeichnis fuer Version 1.5 ') ; gotoxy(20,8) ; write('Bildschirm Befehle ! Disk Befehle ') ; gotoxy(18,9) ; write('----------------------+----------------------') ; gotoxy(20,10) ; write('^X : naechste Datei ! N : neue DOS-Disk ') ; gotoxy(20,11) ; write('^E : Datei zurueck ! D : SubDir waehlen') ; gotoxy(20,12) ; write('^D : naechste Spalte! R : RootDir ') ; gotoxy(20,13) ; write('^S : Spalte zurueck ! I : DOS Diskinfo ') ; gotoxy(20,14) ; write(' ! S : Diskspace CP/M') ; gotoxy(20,16) ; write('Datei Befehle ! Copy verlassen') ; gotoxy(18,17) ; write('----------------------+----------------------') ; gotoxy(20,18) ; write('T : Tag Datei ! X : CP/M') ; gotoxy(20,19) ; write('U : Untag Datei ! ') ; gotoxy(20,20) ; write('C : copy Datei ! ') ; gotoxy(20,21) ; write('G : Group copy ! W : schreiben auf') ; gotoxy(20,22) ; write('F : Dateigroesse ! DOS-Diskette') ; gotoxy(20,24) ; write(' zurueck mit beliebiger Taste ! '); read(kbd,Antwort) ;Antwort := ' ' ; Clrfenster ; Rahmen ; Display_dir ; Display(0) ; end ; {-----------------------------------------------------------------------------} Function NeueGruppe(AGr: Integer): Integer; { Berechnet aus der alten Gruppennummer den Offset in der } { FAT und die neue Gruppennummer. } Var Offset, Hilf : Integer; Begin Offset := AGr * 3 div 2; Hilf := FATBuf[Offset+1] shl 8 + FATBuf[Offset]; If Odd(AGr) Then NeueGruppe := Hilf shr 4 Else NeueGruppe := Hilf and $FFF ; { Falls alte Gruppe ungerade obere 12 Bits, } { sonst untere 12 Bits als neue Gruppe } End; { NeueGruppe } {-----------------------------------------------------------------------------} Procedure ScanDirectory(dirspur,dirsektor,maxein : integer ; root : boolean) ; { Dient zum Einlesen und Sortieren von Haupt- und Unter - } { Inhaltsverzeichnissen der MS-Dos-Diskette } var nextClu : boolean ; gruppe : integer ; count : integer ; {$A-} Procedure Quick_Sort(Anfang,Ende : integer ) ; var VElement : String[32] ; links,rechts : integer ; begin links := Anfang ; rechts := Ende ; VElement := Entry[(Anfang+Ende) shr 1] ; repeat while Entry[links] < Velement do links := succ(links) ; while Entry[rechts] > Velement do rechts := pred(rechts) ; if links <= rechts then begin temp := Entry[rechts] ; Entry[rechts] := Entry[links] ; Entry[links] := Temp ; links := succ(links) ; rechts := pred(rechts); end ; until links > rechts ; if Anfang < rechts then quick_sort(Anfang,rechts) ; if Ende > links then quick_sort(links,Ende) ; end ; {$A+} Begin count := 0 ; if not root then gruppe := Startgruppe ; Ende := False; nextClu := false ; Anzahl := -1; SubDirs := 0 ; While not Ende do Begin Offset := 0; RWSektor(MSDrive,DirSpur,DirSektor,False,DatBuf[1]); Repeat IF (DatBuf[1][Offset] <> 0) and (DatBuf[1][Offset] <> $e5) Then case DatBuf[1][Offset+11] of $28 : begin move(DatBuf[1][offset],Name_of_Disk[1],11) ; Name_of_Disk[0] := chr(11) ; end ; $10,$12 : if DatBuf[1][offset] <> ord('.') then begin SubDirs := succ(SubDirs) ; move(DatBuf[1][offset],SDir[SubDirs][1],32) ; SDir[SubDirs][0] := chr(11) ; end ; $20..$27 : begin Anzahl := Succ(Anzahl); move(DatBuf[1][offset],Entry[Anzahl][1],32) ; Entry[Anzahl][0] := chr(32) ; end ; else end ; { case } count := succ(count) ; Ende := (DatBuf[1][Offset] = 0) or (count = maxein) ; Offset := Offset + 32 Until Ende or (Offset >= SecSiz); if not ende then if nextClu then begin gruppe := Neuegruppe(gruppe) ; if gruppe <= MaxGr then begin gruppe_in_track_sektor(gruppe,DirSpur,DirSektor) ; nextClu := false ; end else ende := true end else begin DirSektor := succ(DirSektor) ; DirSpur := DirSpur + DirSektor div SecpTr ; IF DirSektor >= SecpTr then DirSektor := DirSektor mod SecpTr ; IF root then ende := count > Eintraege else nextClu := true ; end ; End; { While } { Directory zuende } if anzahl > 0 then quick_sort(0,Anzahl) ; End; { ScanDirectory } {-----------------------------------------------------------------------------} procedure RootDir ; begin ClrFenster ; ActDir := 'ROOT ' ; Name_of_Disk := 'Kein Name'; repeat LiesFAT; if nodisk then begin Meldung('keine MS-DOS Diskette !!! Neue Disk (J/N) ?') ; read(kbd,Antwort) ; Antwort := Upcase(Antwort) ; Meldung(' ') ; if antwort = 'N' then begin gotoxy(1,24) ; halt ; end ; end ; until not nodisk ; r := 0 ; DirTr := 0; Dirsec := 5 ; ScanDirectory(Dirtr,Dirsec,Eintraege,true) ; Rahmen ; Display_Dir ; dirsel := 0 ; Display(0) ; end ; {-----------------------------------------------------------------------------} Procedure Lies; { Liest die Datei von der MS-DOS-Diskette in einen Datenbuffer bis } { zum Dateiende oder bis der Buffer voll ist. } Var z, Gruppe : Integer; Track, Sektor : integer; Ende : Boolean; Begin { Lies } Gruppe := Startgruppe; Ende := False; if NSecs > BufGr then begin z := BufGr ; NSecs := NSecs - Bufgr ; end else begin z := NSecs ; NSecs := 0 ; end ; SetMultiIO(z) ; z := 1; While not Ende and (z <= BufGr) and not Abbruch do Begin Gruppe_in_Track_Sektor(Gruppe,Track,Sektor); If not Abbruch then begin Gruppe := NeueGruppe(Gruppe) ; If (Gruppe >= $ff8) and (Gruppe <= $fff) Then Ende := True ; RWSektor(MSDrive,Track,Sektor,False,DatBuf[z]); if Ende and (fs < SecSiz) then fillchar(Datbuf[z][fs],SecSiz - fs,$1A) ; z := succ(z) ; If not Abbruch and (SecpGr = 2) Then begin Sektor := succ(Sektor); Track := Track + (Sektor div SecpTr); Sektor := Sektor mod SecpTr; RWsektor(MSDrive,Track,Sektor,False,DatBuf[z]) ; if Ende and (fs > SecSiz) then begin fs := fs - SecSiz ; fillchar(Datbuf[z][fs],SecSiz - fs,$1A) ; z := succ(z) ; end; if (not Ende) or (fs = 0) then z := succ(z) ; end ; End; End; { While } Dateiende := Ende; Startgruppe := Gruppe; benutzt := pred(z) ; End; { Lies } {-----------------------------------------------------------------------------} procedure Copy_Setup( Message : anystring ) ; begin Abbruch := false ; gotoxy(1+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write(' ') ; gotoxy(16+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write(' ') ; Meldung(message) ; read(kbd,destlw) ; destlw := Upcase(destlw) ; if destlw in ['A'..'P'] then write(destlw,': User ') else Abbruch := true ; user := 0 ; read(kbd,c) ; if c in ['0'..'9'] then user := 10*User + ord(c)-48 else Abbruch := true ; write(c) ; read(kbd,c) ; if c in ['0'..'9'] then begin user := 10*User + ord(c)-48 ; write (c) ; end else if c <> #13 then Abbruch := true ; if user > 15 then Abbruch := true ; end ; {-----------------------------------------------------------------------------} procedure Filecopy ; begin if Abbruch then begin Wait(100); meldung(' ') ; exit ; end ; f := 65536.*ord(Entry[dirsel+r][31])+ 256.*ord(Entry[dirsel+r][30])+ ord(Entry[dirsel+r][29]) ; if SecpGr = 2 then fs := trunc(frac(f/1024.0)*1024.0) else fs := trunc(frac(f/512.0)*512.0) ; NSecs := trunc(f/SecSiz) ; cpmname := destlw+':'+Filename(dirsel+r) ; i := 1 ; while length(cpmname)-3 > i do if cpmname[i] = ' ' then delete(cpmname,i,11-i) else i := succ(i) ; Bdos(32,user) ; Assign(CPMFile,CPMName); {$i-} reset(CPMFile) ; if IOResult = 0 then begin write(' existiert, Ueberschreiben (J/N) ? ') ; read(kbd,c) ; c:=UpCase(c) ; write(c) ; if c = 'J' then Rewrite(CPMFile) else begin Wait(100) ; Meldung(' ') ; exit ; end ; end else Rewrite(CPMFile); {$i+} if IOResult <> 0 then begin abbruch := true ; selected[dirsel+r] := true ; Meldung('Direktory ist voll weiter mit ') ; readln ; Meldung(' ') ; end ; StartGruppe := ord(Entry[dirsel+r][28]) shl 8 +ord(Entry[dirsel+r][27]) ; Dateiende := False; erst := True; While not Dateiende and not Abbruch do Begin Lies; If not Abbruch Then begin { Schreib Datenpuffer Auf CP/M Diskette bis } Reset(CPMFile) ; { zum Dateiende oder bis der Puffer leer ist } Seek(CPMFile,FileSize(CPMFile)) ; {$i-} BlockWrite(CPMFile,Datbuf,benutzt shl 2); {$i+} If IOResult <> 0 then begin close(CPMFile) ; erase(CPMFile) ; Meldung('Diskette voll, '+Filename(dirsel+r)+' wieder geloescht !') ; selected[dirsel+r] := true ; Wait(300) ; Meldung(' ') ; end else Close(CPMFile) ; End ; End; BDos(32,defUser) ; meldung(' ') ; end ; {-----------------------------------------------------------------------------} Begin { Hauptprogramm } for i := 0 to maxdir do selected[i] := false ; ClrScr; Abbruch := false ; Titel ; Meldung(' '); Init; RootDir ; repeat ; gotoxy(1,22) ; read(kbd,Antwort) ; case Upcase(Antwort) of 'T' : begin selected[dirsel+r] := true ; gotoxy(15+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write('#') ; Display(1) ; end ; 'U' : begin selected[dirsel+r] := false ; gotoxy(15+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write(':') ; Display(1) ; end ; ' ',#13 : Display(1) ; ^J,^X : Display(1) ; ^K,^E : Display(-1) ; ^L,^D : Display(maxzeil) ; ^H,^S : Display(maxzeil) ; 'D' : begin { Subdirs auswaehlen } ClrFenster ; i := 0 ; Abbruch := false ; while ( i+1 <= subdirs) and not Abbruch do begin i := succ(i) ; Meldung('Select '+SDir[i]+' (J/N) ? ') ; read(kbd,Antwort) ; Antwort := Upcase(Antwort) ; write(Antwort) ; Abbruch := ( Antwort = 'J' ) ; end ; Meldung(' ') ; if Abbruch then begin ActDir := Sdir[i] ; StartGruppe := ord(Sdir[i][28]) shl 8 + ord(Sdir[i][27]) ; Gruppe_in_track_sektor(startgruppe,dirtr,dirsec) ; scanDirectory(dirtr,dirsec,maxdir,false) ; end ; r := 0; dirsel := 0 ; Rahmen ; Display_dir ; Display(0) ; end ; 'C' : begin { Kopieren File } Copy_Setup('copy '+Filename(dirsel+r)+' to Drive') ; Filecopy ; Display(1) ; end ; 'G' : begin { Kopieren Marked Files } Copy_Setup('Group-copy to Drive') ; dirsel := 0 ; r := 0 ; Display_Dir ; while not Abbruch and (dirsel <= Anzahl) do begin if Selected[dirsel] then begin selected[dirsel] := false ; if dirsel < maxanz then begin gotoxy(15+(dirsel div maxzeil) shl 4, 7+dirsel mod maxzeil) ; write(':') ; end ; Meldung('Copying '+Filename(dirsel)) ; Filecopy ; end ; dirsel := succ(dirsel) ; end ; Dirsel := 0 ; r := 0 ; Meldung(' ') ; Display(0) ; end ; '/' : Help ; { Hilfsseite ausgeben } 'N' : begin { neue Diskette } ClrFenster ; Meldung('MS-DOS-Diskette einlegen und '); Readln; Meldung(' '); rootdir ; end ; 'S' : begin { Space CP/M Diskette } Meldung('Freier Diskspeicher auf Laufwerk') ; read(kbd,c) ; c := Upcase(c) ; write(c,': ') ; if c in ['A'..'P'] then begin i := BdosHL(26,addr(FreeSek)) ; i := BdosHL(46,ord(c)-65) ; f :=(FreeSek[1]+256.*FreeSek[2]+65536.*FreeSek[3])/8 ; write(f:5:0,' KByte ') ; Wait(750) ; Meldung(' ') ; end ; end ; 'R' : RootDir ; 'F' : begin meldung(Filename(dirsel)+' Filelaenge MS-DOS :') ; f := 65536.*ord(Entry[dirsel][31])+ 256.*ord(Entry[dirsel][30])+ ord(Entry[dirsel][29]) ; write(f:6:0,' Bytes ---> CP/M : ') ; if frac(f/1024) = 0 then f := f/1024 else f := f/1024 + 1 ; write(trunc(f):3,' KByte '); Wait(750) ; Meldung(' ') ; end ; 'I' : Diskinfo ; 'W' : begin assign(CPMFile,'MSWRITE.CHN') ; Chain(CPMFile) ; end ; else end ; until Upcase(Antwort)='X' ; gotoxy(1,24) ; End. Program Schreib_MS_DOS_Disketten ; {============================================================================= Entwickelt auf Commodore PC 128 unter CP/M+ mit einem Diskettenlaufwerk Commodore 1571 nach MC TEDAS ----- Ueberarbeitet, Fehler entfernt, erweitert und umgebaut auf interaktives Utility von Andreas Buchelt Vers 1.3 Wechsel zu MSREAD ueber CHAIN. Vers 1.4 RW-Operationen mit Multi-IO-Unterstuetzung nur noch physikalische Sektoren werden verwendet Kommandos an ZCPR Z-FILER angeglichen Version 1.4 01. Februar 1992 (c) Copyright by Andreas Buchelt Anpassung an andere CP/M plus Systeme : ======================================= Achtung : das Programm kann in dieser Version nur 360K Disketten richtig beschreiben. Dieses Programm darf mit Source weitergegeben werden, aber bitte die Copyright-Vermerke n i c h t entfernen !!! Sollten noch Fehler gefunden werden, so bin ich fuer Hinweise dankbar. Andreas Buchelt Am Muehlbach 17 D 8046 Garching Hinweise : Erarbeitet und getestet mit TURBO-Pascal 3.00 unter CP/M plus ========== mit einer RAM-Floppy !!! Compiliert zu CHN-File in 14,0 s ! MSWRITE.CHN compiliert mit Endadresse 0D700H . Anzahl der DOS- Sektor-Puffer kann der Speichergroesse angepasst werden. ==============================================================================} {$i msdisk.inc } const maxCpm = 255 ; { max 256 Dir-Eintraege bei CP/M } Var AnzSektoren : Integer ; fs : integer ; EndFlag : Boolean ; Name : String14 ; Gruppe : integer ; Entry : Array[0..Maxcpm] of String[12] ; selected : Array[0..Maxcpm] of Boolean ; Temp : String[12] ; tag,monat, jahr,stdn, min : byte ; datpar : array[1..2] of integer ; {$i mswrite.inc } {-----------------------------------------------------------------------------} { initialisiert Bootsektor, loescht FAT und Directory } Procedure Ini_DOS_Disk ; Const oem : array [1..8] of char = 'IGS V1.3' ; dnam : array [1..11] of char = 'CPM-->MSDOS' ; var count,Track,Sektor : integer ; begin Abbruch := false ; Meldung('Achtung ! Alle Daten der DOS-Diskette gehen verloren. Ok (J/N) ?') ; read(kbd,Antwort) ; Antwort := Upcase(Antwort) ; write(Antwort) ; if Antwort <> 'J' then begin Abbruch := true ; Meldung(' ') ; exit ; end ; Fillchar(Datbuf[1],512,0) ; move(oem,DatBuf[1,3],8) ; DatBuf[1,$0B] := 0 ; DatBuf[1,$0C] := 2 ; { 512 Bytes Sektorgroesse } DatBuf[1,$0D] := 2 ; { 2 Sektoren = Cluster } DatBuf[1,$0E] := 1 ; DatBuf[1,$0F] := 0 ; { 1 reservierter Sektor } DatBuf[1,$10] := 2 ; { 2 FAT's } DatBuf[1,$11] := lo(112) ; DatBuf[1,$12] := hi(112) ; DatBuf[1,$13] := lo(720) ; DatBuf[1,$14] := hi(720) ; DatBuf[1,$15] := $FD ; { Medium Byte } DatBuf[1,$16] := 2 ; DatBuf[1,$17] := 0 ; { 2 Sektoren = FAT } DatBuf[1,$18] := 9 ; DatBuf[1,$19] := 0 ; { Sektoren / Spur } DatBuf[1,$1A] := 2 ; DatBuf[1,$1B] := 0 ; { Seiten } FatBuf[0] := $FD ; FatBuf[1] := $FF ; FatBuf[2] := $FF ; FillChar(FatBuf[3],1021,0) ; FillChar(DatBuf[2],512,$F6) ; for count := 0 to 15 do DatBuf[2,count shl 5] := 0 ; SetMultiIO(13) ; RWSektor(MSDrive,0,0,true,DatBuf[1]) ; RWSektor(MSDrive,0,1,true,FatBuf) ; RWSektor(MSDrive,0,2,true,FatBuf[512]) ; RWSektor(MSDrive,0,3,true,FatBuf) ; RWSektor(MSDrive,0,4,true,FatBuf[512]) ; Dirsec := 5 ; Sektor := Dirsec ; Track := 0 ; for count := 1 to 6 do begin Sektor := succ(Sektor) ; Track := Track + Sektor div SecpTr ; Sektor := Sektor mod SecpTr ; RWSektor(MSDrive,Track,Sektor,true,DatBuf[2]) ; end ; fillchar(DatBuf[2],32,0) ; move(dnam,DatBuf[2],11) ; DatBuf[2,11] := $28 ; RWSektor(MSDrive,0,Dirsec,true,DatBuf[2]) ; Meldung(' ') ; end ; {-----------------------------------------------------------------------------} Procedure Directory_Eintrag(Gr: Integer) ; { Dient zum Eintrag von Namen und Startgruppe in die Directory der } { MS-DOS-Diskette } Var DirTr, DirSec, Anzahl, k : Byte ; Offset,free_sec,free_adr,free_trk : Integer ; Ende,found,free : Boolean ; Vglname : String14 ; Procedure Loeschen(AGr: Integer) ; { Loescht alle Gruppen in der FAT, bis End of File in } { der FAT erreicht wird. } Var Offset, Hilf, Gruppe : Integer; Begin gruppe := AGr ; repeat Offset := Gruppe * 3 div 2 ; Hilf := FATBuf[Offset+1] shl 8 + FATBuf[Offset]; If Odd(Gruppe) Then begin Gruppe := Hilf shr 4 ; Hilf := Hilf and $000F ; { Falls Gruppe ungerade obere 12 Bits, } end Else begin Gruppe := Hilf and $FFF ; Hilf := Hilf and $F000 ; { sonst untere 12 Bits 0 setzen } end ; FatBuf[Offset] := Hilf and $FF ; FatBuf[Offset+1] := Hilf shr 8 ; until Gruppe >= $FF8 ; End; { Loeschen } Begin DirTr := 0 ; Dirsec := 5 ; RWSektor(MSDrive,Dirtr,Dirsec,false,DatBuf[1]) ; Ende := False ; found := false ; Anzahl := 0 ; While not Ende do Begin Offset := 0 ; Repeat Anzahl := Succ(Anzahl) ; Free := (DatBuf[1][Offset] = 0) or (DatBuf[1][Offset] = $E5) ; if free and not found Then Begin { Freier Platz gefunden } Free_trk := DirTr ; Free_sec := dirsec ; Free_adr := Offset ; found := true end ; if not free and ( DatBuf[1][Offset+11] in [$20..$27] ) then begin Vglname[0] := #11 ; move(DatBuf[1][Offset],Vglname[1],11) ; if VglName = copy(Entry[dirsel+r],1,11) then begin write(' existiert, ueberschreiben (J/N) ? ') ; read(kbd,Antwort) ; Antwort := Upcase(Antwort) ; write(Antwort) ; if Antwort = 'J' then begin DatBuf[1][Offset] := $E5 ; Loeschen(DatBuf[1][Offset+26]+256*DatBuf[1][Offset+27]) ; RWSektor(MSDrive,DirTr,DirSec,true,DatBuf[1]) ; end else begin Abbruch := true ; exit end ; end ; end ; Ende := (DatBuf[1][Offset] = 0) or (Anzahl = Eintraege) ; Offset := Offset + 32 Until Ende or (Offset >= 512) ; If not Ende Then Begin DirSec := succ(Dirsec) ; DirTr := DirTr + DirSec div SecpTr ; DirSec := DirSec mod SecpTr ; RWSektor(MSDrive,DirTr,DirSec,false,DatBuf[1]) End ; End ;{ While } { Platz gefunden oder Directory zuende } If found Then Begin If (free_sec <> dirsec) or (free_trk <> DirTr) then RWSektor(MSDrive,free_trk,free_sec,false,DatBuf[1]) ; For k := 0 to 10 do DatBuf[1][free_adr+k] := Ord(Entry[dirsel+r][k+1]) ; DatBuf[1][free_adr+11] := $20 ; For k := 12 to 21 do DatBuf[1][free_adr+k] := 0 ; bdos(105,addr(datpar)) ; datum(datpar[1],tag,monat,jahr) ; stdn := bcdbin(lo(datpar[2])) ; min := bcdbin(hi(datpar[2])) ; DatBuf[1][free_adr+22] := 0 + min shl 5 ; DatBuf[1][free_adr+23] := min shr 3 + stdn shl 3 ; DatBuf[1][free_adr+24] := tag + monat shl 5 ; DatBuf[1][free_adr+25] := monat shr 3 + (jahr-80) shl 1 ; DatBuf[1][free_adr+26] := Lo(Gr) ; DatBuf[1][free_adr+27] := Hi(Gr) ; DatBuf[1][free_adr+28] := fs shl 7 and $FF ; DatBuf[1][free_adr+29] := fs shr 1 and $FF ; DatBuf[1][free_adr+30] := fs shr 9 ; DatBuf[1][free_adr+31] := 0 ; RWSektor(MSDrive,free_trk,free_Sec,True,DatBuf[1]) End Else Begin Meldung('Directory voll. Weiter mit ') ; selected[dirsel+r] := true ; Abbruch := true ; readln ; Meldung(' ') ; exit ; End End ;{ DirectoryEintrag } {-----------------------------------------------------------------------------} Procedure Schreib_DOS ; { Schreibt Puffer auf die MS-DOS-Diskette und aktualisiert die FAT. } Var z, Track, Sektor : Integer ; Procedure Trageein(var NGr : integer) ; { Dient dazu, eine Gruppe in der FAT als belegt mit dem entsprechenden } { Wert zu kennzeichnen. } Var Hilf,Gr : Integer ; Begin Gr := NGr ; If Dateiende Then Ngr := $FFF Else begin repeat NGr := succ(NGr) ; until Freie_Gruppe(NGr) or (NGr > maxGr) ; If NGr > maxGr Then Begin selected[dirsel+r] := true ; Meldung('Diskette voll ! weiter mit ') ; readln ; Abbruch := true ; Ngr := $FFF ; End ; End ; Offset := Trunc(Gr * 3 shr 1); Hilf := FATBuf[Offset+1] shl 8 + FATBuf[Offset]; If Odd(Gr) Then Hilf := hilf or (NGr shl 4) { Falls Gruppe ungerade obere } Else Hilf := Hilf or NGr ; { sonst untere 12 Bits setzen } FatBuf[Offset] := Hilf and $FF ; FatBuf[Offset+1] := Hilf shr 8 ; End ;{ Trageein } Begin z := 1 ; SetMultiIO(AnzSektoren) ; While z <= AnzSektoren do begin Gruppe_in_Track_Sektor(Gruppe,Track,Sektor) ; RWSektor(MSDrive,Track,Sektor,True,DatBuf[z]) ; z := succ(z) ; if z <= Anzsektoren then begin Sektor := succ(Sektor) ; Track := Track + Sektor div SecpTr ; Sektor := Sektor mod SecpTr ; RWSektor(MSDrive,Track,Sektor,True,DatBuf[z]) ; z := succ(z) ; end ; if ( z > AnzSektoren) and Endflag then Dateiende := true ; Trageein(Gruppe) ; End ; End ;{ SchreibeDatei } {-----------------------------------------------------------------------------} procedure Dir_Setup( Message : anystring ) ; begin gotoxy(1+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write(' ') ; gotoxy(16+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write(' ') ; Meldung(message) ; end ; {-----------------------------------------------------------------------------} procedure Filecopy ; var count : integer ; begin CPMName := DestLW+':'+Filename(Dirsel+r) ; i := 1 ; while length(CPMName)-3 > i do if CPMName[i] = ' ' then delete(CPMName,i,11-i) else i := succ(i) ; Assign(CPMFile,CPMName) ; Reset(CPMFile) ; fs := Filesize(CPMFile) ; if fs div 8+1 > Disk_Space then begin Meldung('Zu wenig Platz auf der MS-DOS Diskette. weiter mit ') ; readln ; Meldung(' ') ; selected[dirsel+r] := true ; exit ; end ; i := 1 ; repeat i := succ(i) ; until Freie_Gruppe(i) or ( i >= maxGr ) ; Startgruppe := i ; Directory_Eintrag(i) ; Gruppe := Startgruppe ; Dateiende := False ; Endflag := false ; fs := filesize(CPMFile) ; count := 0 ; while (count <= int(fs/4/BufGr)) and not Abbruch do begin benutzt := 4*BufGR*succ(count)-fs ; if benutzt <= 0 then benutzt := 4*BufGr else begin benutzt := 4*BufGr - benutzt ; Endflag := true ; end ; Reset(CPMFile) ; Seek(CPMFile,4*Bufgr*count) ; Blockread(CPMFile,DatBuf,benutzt) ; if benutzt mod 4 = 0 Then AnzSektoren := benutzt div 4 Else AnzSektoren := benutzt div 4 + 1 ; Schreib_Dos ; count := succ(count) ; end ; SetMultiIO(4) ; RWSektor(MSDrive,0,1,True,FatBuf) ; { FatBuf auf Diskette schreiben } RWSektor(MSDrive,0,2,True,FatBuf[512]) ; RWSektor(MSDrive,0,3,True,FatBuf) ; RWSektor(MSDrive,0,4,True,FatBuf[512]) ; { ab Sektor 3 steht das Doppel der FAT } end ; {-----------------------------------------------------------------------------} Begin { Hauptprogramm } for i := 0 to maxcpm do selected[i] := false ; ClrScr; Abbruch := false ; Titel ; Meldung(' '); Init; DestLW := chr(CurDrv+65) ; user := defUser ; Rahmen ; repeat LiesFAT; if nodisk then begin Meldung('keine DOS Diskette !'+ ' Neue Disk, Disk Initialisieren oder Ende (N/I/E) ?') ; repeat read(kbd,Antwort) ; Antwort := Upcase(Antwort) ; until Antwort in ['E','I','N'] ; Meldung(' ') ; case Antwort of 'E' : halt ; 'I' : Ini_DOS_Disk ; else end ; end ; until not nodisk ; scanDirectory ; dirsel := 0 ; r := 0 ; Display_dir ; display(0) ; Repeat gotoxy(1,22) ; read(kbd,Antwort) ; Antwort := Upcase(Antwort) ; case Antwort of 'T' : begin selected[dirsel+r] := true ; gotoxy(15+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write('#') ; display(1) ; end ; 'U' : begin selected[dirsel+r] := false ; gotoxy(15+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; write(':') ; display(1) ; end ; ^J,^X : display(1) ; ' ',#13 : display(1) ; ^K,^E : display(-1) ; ^L,^D : display(maxzeil) ; ^H,^S : display(-maxzeil) ; 'C' : begin Dir_Setup('Copying '+Filename(dirsel+r)) ; Filecopy ; Meldung(' ') ; display(1) ; end ; 'G' : begin { Kopieren Marked Files } Abbruch := false ; Dir_Setup('Group-Copy to MS-DOS Disk') ; Wait(100) ; dirsel := 0 ; r := 0 ; Display_Dir ; While not Abbruch and (dirsel <= Anzahl) do begin if Selected[dirsel] then begin selected[dirsel] := false ; if dirsel <= maxanz then begin gotoxy(15+(dirsel div maxzeil) shl 4, 7+dirsel mod maxzeil) ; write(':') ; end ; Meldung('Copying '+Filename(dirsel)) ; Filecopy ; end ; dirsel := succ(dirsel) ; end ; Dirsel := 0 ; r := 0 ; Meldung(' ') ; display_Dir ; display(0) ; end ; '/' : Help ; { Hilfsseite ausgeben } 'N' : begin { neue Diskette } Abbruch := false ; ClrFenster ; Meldung('Directory von Laufwerk') ; read(kbd,destlw) ; destlw := Upcase(destlw) ; if destlw in ['A'..'P'] then write(destlw,': User ') else Abbruch := true ; user := 0 ; read(kbd,c) ; if c in ['0'..'9'] then user := 10*User + ord(c)-48 else Abbruch := true ; write(c) ; read(kbd,c) ; if c in ['0'..'9'] then user := 10*User + ord(c)-48 else if c <> #13 then Abbruch := true ; write (c) ; if user > 15 then Abbruch := true else BDos(32,User) ; if Abbruch then destlw := 'A' else begin Rahmen ; Scandirectory ; end ; Display_Dir ; Dirsel := 0 ; r := 0 ; display(0) ; Meldung(' '); end ; 'I' : begin dir_setup(' ') ; Ini_DOS_Disk ; display(0) ; end ; 'S' : begin Dir_Setup(' ') ; write(Disk_Space,' KByte frei auf MS-DOS Diskette') ; Wait(500) ; Meldung(' ') ; display(0) ; end ; 'F' : begin Dir_setup('Dateilaenge :') ; CPMName := DestLW+':'+Filename(Dirsel) ; i := 1 ; while length(CPMName)-3 > i do if CPMName[i] = ' ' then delete(CPMName,i,11-i) else i := succ(i) ; Assign(CPMFile,CPMName) ; Reset(CPMFile) ; fs := Filesize(CPMFile) ; if fs mod 8 = 0 then fs := fs div 8 else fs := fs div 8 + 1 ; write(fs:4,' KByte ') ; Wait(7500) ; Meldung(' ') ; display(0) ; end ; 'R' : begin Assign(CPMFile,'MSREAD.CHN') ; Chain(CPMFile) ; end ; end ; Until Antwort = 'X' ; Gotoxy(1,24) ; Bdos(32,defUser) ; End. Program MSWASH ;(* MSCOPY *) { Version 1.1 01. Februar 92 (c) Copyright by Andreas Buchelt Anpassung an andere CP/M plus Systeme : ======================================= MSCOPY besteht aus den Teilen MSCOPY.COM, MSREAD.CHN und MSWRITE.CHN, die sich alle auf dem gleichen Laufwerk befinden. Der Zugriff auf die DOS-Dis- ketten erfolgt ueber CPM+ indirekte BIOS-Calls. Multi-IO wird unterstuetzt, soweit im BIOS implementiert. Aenderungen sind nur notwendig, wenn das BIOS nicht ueber Sektor-Wrap auf die 2. Seite umschalten kann. Der DPB muss fuer das DOS-Laufwerk vor dem Programmstart folgende Form haben: DW 72 ; 72 128-Byte Records /Track DB 4 ; 2 KByte CP/M-Blockgroesse DB 15 ; Blockmask DB 1 ; 1 Extent (32K / Dir) DW 179 ; 180 Blocks = 360 K DW 0 ; keine Dirs !!! DB 0 ; keine Dir-Bloaecke DB 0 ; DW 8000 ; fixed Media, keine Dirs checken DW 0 ; keine Systracks DB 2 ; Sektorlaenge 512 Byte DB 3 ; Sektor Maske Dieses Programm darf mit Source weitergegeben werden, aber bitte die Copyright-Vermerke n i c h t entfernen !!! Sollten noch Fehler gefunden werden, so bin ich fuer Hinweise dankbar. Andreas Buchelt Am Muehlbach 17 D 8046 Garching Hinweise : Erarbeitet und getestet mit TURBO-Pascal 3.00 unter CP/M plus ========== mit einer RAM-Floppy ! Compiliert zu COM-File in 3,0 s ! MSCOPY.COM compiliert mit Endadresse 0D700H . Anzahl der DOS- Sektor-Puffer kann der Speichergroesse angepasst werden. ==============================================================================} {$imsdisk.inc} var chainfile : file ; begin MSDrive := 2; { Standard DOS-LW = C: systemabgengig !! } while true do begin clrscr ; gotoxy(18,5) ; write('MS-DOS Disketten unter CPM-plus lesen und schreiben') ; gotoxy(18,6) ; write('===================================================') ; gotoxy(10,10) ; write('MS-DOS Diskette in Laufwerk ',chr(MSDrive+65),': einlegen.') ; gotoxy(8,12) ; write('Disk-Parameter-Block fuer Laufwerk ',chr(MSDrive+65),': muss ') ; write('korrekt gesetzt sein.') ; gotoxy(8,13); write('Seitenumschaltung erfolgt ueber Sektorueberlauf !') ; gotoxy(10,15) ; write('Lesen MS-Disk ') ; gotoxy(10,16) ; write('Schreiben MS-Disk ') ; gotoxy(10,17) ; write('DOS-Laufwerk wechseln ') ; gotoxy(10,18) ; write('Exit --->') ; repeat read(kbd,c) ; c := upcase(c) ; until (c = 'R') or (c = 'W') or (c = 'X') or (c = 'C') ; case c of 'R' : begin Assign(chainfile,'MSREAD.CHN') ; Chain(chainfile) ; end ; 'W' : begin Assign(chainfile,'MSWRITE.CHN') ; Chain(chainfile) ; end ; 'C' : begin gotoxy(8,22) ; write('Enter new DOS-Drive : ') ; readln(c) ; c := upcase(c) ; MSDrive := ord(c) - 65 ; CurDrv := BDos(25) ; { Rette aktuelles LW } destlw := chr(CurDrv + 65 ) ; dummy := BDos(14,MSDrive) ; { existiert MSDOS-LW ? } BDos(14,CurDrv) ; if dummy <> 0 then begin meldung('MS-DOS-Laufwerk existiert nicht !? ') ; halt ; end ; end ; 'X' : halt ; end ; end ; end. Const Blocksize = 511 ; { physikalische Blockgroesse unter MS-DOS } SecSiz = 512 ; SecpTr = 18 ; { 2 * 9 Secs, Bios wechselt Seite ! (360K) } SecpGr = 2 ; { 2 Sectoren = 1 Cluster (360K) } DatStart = 12 ; { 1. Cluster in Sector 10 (360K) } Eintraege = 111 ; { 112 Dirs (360K) } BufGr = 40 ; { 56 fuer COM-File mit Ende bei F000H } maxgr = 355 ; { 355 Cluster auf MS-DOS Diskette } maxzeil = 14 ; { Directory wird in 5 Spalten und } maxanz = 70 ; { 14 Zeilen angezeigt. ( = 70 Dirs ) } { ********* Achtung BufGr muss eine gerade Zahl sein! ********* } Type tBuff = Array[0..Blocksize] of Byte ; String14 = String[14] ; String32 = string[32] ; Anystring = String[80] ; Var MSDrive : byte ; { Laufwerk in dem sich die MS-DOS } { Diskette befindet } Psector, CurDrv, dirsel, defUser, i, StartGruppe, benutzt, dummy, pointtodph : Integer ; DPH : ^Integer Absolute pointtodph ; FATBuf : Array[0..1023] of Byte ; DatBuf : Array[1..BufGr] of tBuff ; CPMName, ActDir : String14 ; Dateiende, erst, Abbruch : Boolean ; Antwort, DestLW, c : Char ; User, Anzahl, Anzeig : Integer ; Offset,r,DirSec,DirTr : Integer ; Ende, Nodisk : Boolean ; CPMFile : File; {-----------------------------------------------------------------------------} Procedure Meldung(Meldetext: Anystring) ; { Dient zur Ausgabe einer Meldung in der Menuzeile 22 } Begin GotoXY(1,22) ;ClrEol ; Write(' ',Meldetext,' ') ; End ; { Meldung } {-----------------------------------------------------------------------------} Procedure Wait(centisec : integer) ; var i : integer ; Begin i := centisec ; repeat delay(10) ; i := pred(i) ; until keypressed or (i = 0) ; End; {-----------------------------------------------------------------------------} Function Ubios(FN, PA, PBC, PDE, PHL: Integer): Integer ; { Da unter CP/M 3.0 BIOS-Funktionen ueber BDOS-Funktion 50 aufgerufen } { werden, wird diese Funktion benutzt. vgl. mc Heft 3/85 } Type ParameterBlock = Record func, Areg : Byte ; BCreg, DEreg, HLreg : Integer ; End ; Var BiosPB : ParameterBlock ; Result : Integer ; Begin With BiosPB do Begin func := FN ; Areg := PA ; BCreg := PBC ; DEreg := PDE ; HLreg := PHL ; End ; Result := 0 ; Case FN of 2,3,7,13,14,15,17,18,19,24: Result := Bdos(50, Addr (BiosPB)) ; 9,16,20,22,25: Result := BdosHL(50, Addr (BiosPB)) ; Else Bdos(50, Addr (BiosPB)) ; End ; Ubios := Result ; End ; { Ubios } {-----------------------------------------------------------------------------} Procedure Init ; Begin dummy := BDosHL(12) ; { Teste auf CPM plus } if dummy < 48 then begin meldung('Ohne CP/M-Plus geht da leider nichts ! ') ; halt ; end ; CurDrv := BDos(25) ; { Rette aktuelles LW } destlw := chr(CurDrv + 65 ) ; dummy := BDos(14,MSDrive) ; { existiert MSDOS-LW } if dummy <> 0 then begin meldung('MS-DOS-Laufwerk existiert nicht !? ') ; halt ; end ; BDos(14,CurDrv) ; defUser := BDos(32,255) ; ActDir := 'ROOT' ; End ; { Init } {-----------------------------------------------------------------------------} Procedure SetMultiIO(Count : Integer) ; Begin i := Ubios (23, 0, Count, 0, 0) ; { Count Sektoren lesen } End; {-----------------------------------------------------------------------------} Procedure RWSektor(Dr,Tr,Sec : Integer ; Schreib: Boolean ; Var SecBuf ) ; { Liest einen physikalischen Sektor von Diskette in SecBuf, } { bzw. schreibt SecBuf auf Diskette, je nach Wert von Schreib. } Begin if abs(tr) > 39 then begin write('^M auf Spur ',tr:4,' kann nicht zugegriffen werden. ', 'Fehler beim Umsetzen Cluster in Spur und Sektor ') ; Wait(500) ; exit ; end ; pointtodph := Ubios (9, 0, Dr, 1, 0) ; { Drive auswaehlen } Psector := Ubios (16, 0, Sec, DPH^, 0) ; { phys. Sektor berechnen } i := Ubios (10, 0, Tr, 0, 0) ; { Spur waehlen } i := Ubios (11, 0, Psector, 0, 0) ; { Sektor waehlen } i := Ubios (12, 0, Addr(SecBuf), 0, 0) ; { DMA-Adresse waehlen } i := Ubios (28, 1, 0, 0, 0) ; { Bank waehlen } If Schreib Then i := Ubios (14, 0, 0, 0, 0) { phys. Sektor schreiben } Else i := Ubios (13, 0, 0, 0, 0) ; { phys. Sektor lesen } if i <> 0 then Meldung('Fehler bei DiskIO auf MS-DOS Diskette') ; dummy := UBios (9, 0, ord(destlw)-65, 1, 0) { Zurueck auf CP/M-Drive } End ;{ RWSektor} {-----------------------------------------------------------------------------} Procedure LiesFAT ; { Liest die File-Allocation-Table in einen Buffer } Begin nodisk := false ; RWSektor(MSDrive,0,1,false,FATBuf) ; RWSektor(MSDrive,0,2,false,FATBuf[512]) ; if (FATBuf[1] <> $FF) and (FATBuf[2] <> $FF) then Nodisk := true ; End ; { LiesFAT } {-----------------------------------------------------------------------------} Procedure Gruppe_in_Track_Sektor(Gr: Integer ; Var Tr, Sec: integer) ; { Berechnet aus der Gruppennummer Spur und Sektor auf der Diskette. } Var weiter : Char ; Begin Gr := Gr - 2 ; Gr := Gr * SecpGr ; Gr := Gr + DatStart ; { Start der Daten } Tr := Gr div SecpTr ; Sec := Gr mod SecpTr ; End ; { Gruppe_in_Track_Sektor } {-----------------------------------------------------------------------------} procedure ClrFenster ; begin for i := 5 to 21 do begin gotoxy(1,i) ; clreol ; end ; end ; {-----------------------------------------------------------------------------} function Freie_Gruppe (Gr : integer) : boolean ; { Dient zur Ueberpruefung, ob in der FAT die Gruppe GR frei ist. } var Offset,hilf : integer ; begin Offset := Gr * 3 div 2 ; Hilf := FatBuf[Offset] + 256 * FatBuf[Offset+1] ; if odd(Gr) then Freie_Gruppe := ((hilf shr 4) = 0) else Freie_Gruppe := ((hilf and $FFF) = 0) ; end ; { Freie_Gruppe } {-----------------------------------------------------------------------------} function Disk_Space : integer ; var i,temp : integer ; begin Temp := 0 ; for i := 2 to maxGr do if Freie_Gruppe(i) then temp := Succ(temp) ; Disk_Space := Temp ; end ; {-------------------------------------------------------------------------} FUNCTION bcdbin(BCDVAL : Byte) : Byte ; begin Inline( $21/BCDVAL/ (* START: LD HL,BCDVAL ; HL --> Parameter *) $E6/$0F/ (* AND 0FH ; A ist schon BCD-Zahl *) $4F/ (* LD C,A ; lower Nibble in C *) $7E/ (* LD A,(HL) ; Higher Nibble *) $E6/$F0/ (* AND 0F0H ; maskieren A = HNib*16 *) $0F/ (* RRCA ; HNib * 8 *) $47/ (* LD B,A ; in B retten *) $0F/ (* RRCA ; HNib * 4 *) $0F/ (* RRCA ; A = HNib * 2 *) $80/ (* ADD A,B ; A = HNib * 10 *) $81/ (* ADD A,C ; A = Hnib * 10 + LNib *) $23/ (* INC HL ; TURBO will es nun *) $77/ (* LD (HL),A ; mal so haben *) $00) ; end ; {------------------------------------------------------------------------} PROCEDURE Datum(DATCNT : Integer ; VAR TAG,MONAT,JAHR : Byte ) ; begin Inline( $18/$0D/ (* START: JR DATUM ; um Tabelle herum *) $1F/$1C/$1F/$1E/ (* MONTAB: DEFB 31,28,31,30,31,30 *) $1F/$1E/ (* *) $1F/$1F/$1E/$1F/ (* DEFB 31,31,30,31,30,31 *) $1E/$1F/ (* *) $FF/ (* DEFB 0FFH ; Begrenzer *) $EB/ (* DATUM: EX DE,HL ; DE auf CP/M plus Datum *) $3E/$4D/ (* LD A,77 ; DE ist Wertparameter ! *) $2A/JAHR/ (* LD HL,(JAHR) ; HL auf JAHR Variable *) $77/ (* LD (HL),A ; Jahr := 78-1 *) $06/$00/ (* LD B,0 *) $3E/$01/ (* LD A,1 ; Schaltjahr Zaehler *) $2A/JAHR/ (* NXTJHR: LD HL,(JAHR) ; Schleife fuer Jahr *) $34/ (* INC (HL) *) $0E/$1C/ (* LD C,28 ; Februar mit 28 Tagen *) $21/*-30/ (* LD HL,MONTAB+1 ; Dort steht der Februar *) $28/$06/ (* JR Z,NOSWIT ; 2000 kein Schaltjahr *) $3C/ (* INC A ; *) $E6/$03/ (* AND 3 ; Z --> Schaltjahr *) $20/$01/ (* JR NZ,NOSWIT ; kein Schaltjahr *) $0C/ (* INC C ; Februar mit 29 Tagen *) $71/ (* NOSWIT: LD (HL),C ; und in Tabelle *) $2B/ (* DEC HL ; HL auf Januar *) $4E/ (* NXTMON: LD C,(HL) ; Schleife fuer Monat *) $23/ (* INC HL ; Monat mit C Tagen *) $0C/ (* INC C ; HL auf naechsten Monat *) $28/$E8/ (* JR Z,NXTJHR ; C = FF --> neues Jahr *) $0D/ (* DEC C ; BC Tage abziehen *) $EB/ (* EX DE,HL ; HL verbleibende Tage *) $B7/ (* OR A ; *) $ED/$42/ (* SBC HL,BC ; HL Tage Monatsende *) $EB/ (* EX DE,HL ; in DE *) $28/$02/ (* JR Z,FERTIG ; *) $30/$F1/ (* JR NC,NXTMON ; und naechsten Monat *) $EB/ (* FERTIG: EX DE,HL ; Ergebnis steht *) $09/ (* ADD HL,BC ; HL Tag des Monats *) $7D/ (* LD A,L ; in TAG zurueck *) $2A/TAG/ (* LD HL,(TAG) *) $77/ (* LD (HL),A *) $EB/ (* EX DE,HL ; HL = Monat +1 *) $11/*-67/ (* LD DE,MONTAB ; DE addr(Monat[0]) *) $B7/ (* OR A ; Carry weg *) $ED/$52/ (* SBC HL,DE ; 1=Jannuar 2= usw. *) $7D/ (* LD A,L ; in MONAT zur}eck *) $2A/MONAT/ (* LD HL,(MONAT) *) $77/ (* LD (HL),A *) $00) ; end ; {-----------------------------------------------------------------------------} Function Filename(n : integer) : String14 ; begin Filename := copy(Entry[n],1,8)+'.'+copy(Entry[n],9,3) ; end ; {-----------------------------------------------------------------------------} procedure Titel ; begin gotoxy(10,1) ; writeln('*** Ingenious Systems CP/M ---> MS-DOS Copy Utility *** '); gotoxy(10,2) ; writeln(' from Andreas Buchelt Copyright (c) 1988'); end ; {-----------------------------------------------------------------------------} procedure Rahmen ; begin gotoxy(20,3) ; write('Verzeichnis von Laufwerk ',DestLW,':') ; write(' User : ',user:2) ; gotoxy(25,5) ; write(' fuer Hilfe fuer Exit') ; end ; {-----------------------------------------------------------------------------} procedure Display_Dir ; var i : integer ; begin if Anzahl < maxanz then Anzeig := Anzahl else Anzeig := maxanz-1 ; i := 0 ; while (i <= Anzeig) and ( i+r-1 < Anzahl) do begin gotoxy(2+(i div maxzeil) shl 4,7+i mod maxzeil) ; Entry[i][0] := chr(11) ; write(copy(Entry[i+r],1,8),'.',copy(Entry[i+r],9,3),' ') ; if selected[i+r] then write('#') else write(':') ; i := succ(i) ; end ; if maxanz-1 > Anzahl-r then begin gotoxy(2+(i div maxzeil) shl 4,7+i mod maxzeil) ; write('--------------') ; i := succ(i) ; while i mod maxzeil <> 0 do begin gotoxy(2+(i div maxzeil) shl 4,7+i mod maxzeil) ; write(' ') ; i := succ(i) ; end ; end ; end ; {-----------------------------------------------------------------------------} procedure Display( weiter : integer ) ; procedure mark( switch : boolean ) ; begin gotoxy(1+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; if switch then write('>') else write(' ') ; gotoxy(16+(dirsel div maxzeil) shl 4,7+dirsel mod maxzeil) ; if switch then write('<') else write(' ') ; end ; begin Mark(false) ; dirsel := dirsel + weiter ; if anzahl < 0 then begin Meldung('Keine Datei in diesem Verzeichnis') ; Wait(500) ; Meldung(' ') ; exit ; end ; if dirsel < 0 then begin dirsel := 0 ; if (Anzahl > maxanz-1) and (r > 0) then begin dirsel := maxzeil ; r := r - maxzeil ; Display_Dir ; end ; end ; if dirsel > Anzahl then begin dirsel := 0 ; r := 0 ; end ; if r+dirsel > Anzahl then begin dirsel := 0 ; r := 0 ; Display_Dir ; end ; if dirsel > anzeig then begin r := r + maxzeil ; dirsel := maxanz - maxzeil ; Display_Dir ; end ; mark(true) ; end ; {-----------------------------------------------------------------------------} procedure Help ; begin for i:= 3 to 24 do begin gotoxy(1,i) ; ClrEol ; end ; gotoxy(20,5) ; write(' Befehlsverzeichnis fuer Version 1.4 ') ; gotoxy(20,8) ; write('Bildschirm Befehle ! Disk Befehle ') ; gotoxy(18,9) ; write('----------------------+----------------------') ; gotoxy(20,10) ; write('^X : naechste Datei ! N : neue CP/M-Disk') ; gotoxy(20,11) ; write('^E : Datei zurueck ! ') ; gotoxy(20,12) ; write('^D : naechste Spalte! S : Diskspace DOS ') ; gotoxy(20,13) ; write('^S : Spalte zurueck ! I : DOS-Disk erase') ; gotoxy(20,15) ; write('Datei Befehle ! Copy verlassen') ; gotoxy(18,16) ; write('----------------------+----------------------') ; gotoxy(20,17) ; write('T : Tag Datei ! ') ; gotoxy(20,18) ; write('U : Untag Datei ! ') ; gotoxy(20,19) ; write('C : copy Datei ! X : CP/M') ; gotoxy(20,20) ; write('G : Group copy ! R : lesen von DOS-') ; gotoxy(20,21) ; write('F : Dateigroesse ! Diskette') ; gotoxy(20,24) ; write(' zurueck mit beliebiger Taste ! '); read(kbd,Antwort) ;Antwort := ' ' ; Clrfenster ; gotoxy(1,24) ; ClrEol ; gotoxy(1,5) ; ClrEol ; Rahmen ; Display_dir ; display(0) ; end ; {-----------------------------------------------------------------------------} Procedure ScanDirectory ; { Dient zum Einlesen und Sortieren des } { Inhaltsverzeichnis der CP/M Diskette } var Dirbuf : Array[0..127] of byte ; FCB : Array[0..35] of Byte ; {$A-} Procedure Quick_Sort(Anfang,Ende : integer ) ; var VElement : String[12] ; links,rechts : integer ; begin links := Anfang ; rechts := Ende ; VElement := Entry[(Anfang+Ende) div 2] ; repeat while Entry[links] < Velement do links := succ(links) ; while Entry[rechts] > Velement do rechts := pred(rechts) ; if links <= rechts then begin temp := Entry[rechts] ; Entry[rechts] := Entry[links] ; Entry[links] := Temp ; links := succ(links) ; rechts := pred(rechts); end ; until links > rechts ; if Anfang < rechts then quick_sort(Anfang,rechts) ; if Ende > links then quick_sort(links,Ende) ; end ; {$A+} Begin AnZahl := -1 ; FCB[0] :=ord(DestLW)-64 ; for i:= 1 to 11 do FCB[i] := ord('?') ; for i := 12 to 35 do FCB[i] := 0 ; BDos(26,Addr(DirBuf)) ; i := BDos(17,addr(FCB)) ; if i <> $FF then begin Anzahl := succ(Anzahl) ; Entry[0][0] := #11 ; move(DirBuf[32*i+1],Entry[0][1],11) ; repeat i := BDos(18); if i <> $FF then begin AnZahl := Succ(Anzahl) ; Entry[Anzahl][0] := #11 ; move(DirBuf[32*i+1],Entry[Anzahl][1],11) ; end ; until i = $FF ; end ; if Anzahl > 0 then quick_sort(0,Anzahl) ; End; { ScanDirectory } 1!d!I/\>6AP!!!͙͛! "!:!ͪ! " "*"! *+"͠*!}oEE!"""""!"**s**s**s#r**s#r**s#r!"~*R;"R;"R;" R;"R;"R;"R;"R;"R;"RP"!2!o&"~à" Rʂ"Rʂ"Rʂ"Rʂ"R”"!2!"~à"!2!*~"*! "g*g!0E"M'Ohne CP/M-Plus geht da leider nichts ! !o&"s*s!A}2B!*w&o&"g*g!͒Eb#M#MS-DOS-Laufwerk existiert nicht !? !*s! !o&"oMROOT!G"t!!*t!!k!"m"c}2e"f"h"j*h̀!'Eb$͛ͺ ^M auf Spur *h!&ͺ kann nicht zugegriffen werden. ͺ0Fehler beim Umsetzen Cluster in Spur und Sektor  !7!ä%! !*j!!k!"e!!*f*e^#V!k!"u! !*h!!k!"m! !*u!!k!"m! !*c!!k!"m!!!!!k!"m*e&E)%!!!!!k!"mC%! !!!!k!"m*m!͒E%M%Fehler bei DiskIO auf MS-DOS Diskette ! !*B&!AR!!k!"g!}21*w&!!!!eʹ#*w&!!!!e!ʹ#!e!n&!͒!e!n&!͒}oE&!}21"M"O"Q*Q!R"Q*Q!"Q*Q! "Q*Q!*Os#r*Q!E*Ms#r!!fzʦ&"m!*m͙*m#Ç&"9*9!!"/!e*/n&!!e*/!n&"-*9͋E'*-!V!}2;0'*-!|g}o!}2;*;&!"!!cfzl'"!*!ͧ&Ec'*#"*!#G'*"+*+"C]!`*C]))))):!!k!.e.=!`*C]))))):! !k=!E]!E]:M360K MS-DOS Diskette ͛6'!&ͺ KByte frei !,7!! e. ! !͛ͺ<*** Ingenious Systems MS-DOS ---> CP/M Copy Utility ***  ! !͛ͺ6 from Andreas Buchelt Copyright (c) 1987 !!͛ͺ Name der MS-DOS Diskette :!_:! ͪ ͛ͺ Angezeigtes Directory :!G:! ͪ !!͙!!͛ͺ" fuer Hilfe fuer Exit !!!R͙!!!R͙!!͙͛ͺ SubDirs :  !*T]+fz9*"m! ! *m!È!*m!!]*m#+))))):͛!ͪ *m#)*=!FES**=";b*!F!R";!"]*]*;͸*]*7!R*=}oEʅ+!*]!!N!*]!E!`*])))))!! s͛!`*]*7))))):!!k!ͪ!."!`*]*7))))):! !k!ͪ! " !_*]*7n&Eo+͛!#" {+͛!:" *]#"]h*!F!R*=*7RE\,!*]!!N!*]!E͛ͺ-------------- *]#"]*]!E!͒E\,!*]!!N!*]!E͛ͺ  *]#"]+-}2]!*q!!N!*q!E*]&Eʰ,͛!>" ü,͛! " !*q!!N!*q!E*]&E-͛!<" -͛! " "]!`,*q*]"q*=!Ew-M!Keine Datei in diesem Verzeichnis !,7!! e. D.*q!E-!"q*=!F!R*7!}oE-!"q*7!R"7:**q*=E-!"q!"7*7*q*=E.!"q!"7:**q*;E=.*7!"7!F!R"q:*!`,!!fzo."m!*m͙*m#P.!!͛ͺ& Befehlsverzeichnis fuer Version 1.5  !!͛ͺ)Bildschirm Befehle ! Disk Befehle  !! ͛ͺ-----------------------+---------------------- !! ͛ͺ)^X : naechste Datei ! N : neue DOS-Disk  !! ͛ͺ)^E : Datei zurueck ! D : SubDir waehlen !! ͛ͺ)^D : naechste Spalte! R : RootDir  !! ͛ͺ)^S : Spalte zurueck ! I : DOS Diskinfo  !!͛ͺ) ! S : Diskspace CP/M !!͛ͺ%Datei Befehle ! Copy verlassen !!͛ͺ-----------------------+---------------------- !!͛ͺT : Tag Datei ! X : CP/M !!͛ͺU : Untag Datei !  !!͛ͺC : copy Datei !  !!͛ͺ(G : Group copy ! W : schreiben auf !!͛ͺ)F : Dateigroesse ! DOS-Diskette !!͛ͺ zurueck mit beliebiger Taste !  !ͩ!CD ! }2C|&(:*!],"\*\!!"\!e*\!n&!N!e*\n&"\*\͋Eʓ2*\!V"\ä2*\!|g}o"\*\41!\"\"\*\"\*\"\!`*\*\!V))))): !\!`*\))))):!\:E"3*\#"\2!`*\))))):!\:EN3*\+"\"3*\*\͸E3!`*\))))): !Z]!`*\)))))!`*\))))): !`*\)))))!Z]: *\#"\*\+"\*\*\E2*\*\E3*\*\ͫ2*\*\E4*\*\ͫ21\"}2\"\"\"\!"\*\&}oEN4*k"\!}22!}2\!"=!"T]*2&}oEʇ7!"9*w&*\*\!!e!+)))))))))ʹ#!e!+)))))))))*9n&!͒!e!+)))))))))*9n&!͒}oEn6!e!+)))))))))*9! n&(R_5!e!+)))))))))*9!_!! d!_!! sn6Rs5R5!e!+)))))))))*9n&!.͒E5*T]#"T]!e!+)))))))))*9!]*T]+)))))!! d!]*T]+)))))!! sn6 RBn6*=#"=!e!+)))))))))*9!`*=)))))!! d!`*=)))))!! sn6*\#"\!e!+)))))))))*9n&!*\*\}o}22*9! "9*2&*9!ͥ}oEʥ4*2&}oEʄ7*\&E(7*\-2"\*\!c͸E7*\!\!\&!}2\%7!}22Ä7*\#"\*\*\!"\*\!ͥEa7*\!E"\*\&E}7*\!o}22Ä7!}2\h4*=!Eʢ7!*=ͫ2|&M ROOT !GM Kein Name!_ͥ%*1&EZ8M0keine MS-DOS Diskette !!! Neue Disk (J/N) ? !ͩ!CD *C&}2C! e. *C&!NEZ8!! *1&}oE7!"7!"3!"5*3*5!o!ͨ2(:*!"q!],*k"\!}2\*V]!(E8!("\*V]!(R"V]8*V]"\!"V]*\͑#!"\*\&}o*\!(͸}o*D&}o}oE:*\!\!\&*D&}oE:*\-2"\*\!ͥ*\!͸}oEi9!}2\*w&*\*\!!e*\+)))))))))ʹ#*\&*X]!}oE9!e*\+)))))))))*X]!*X]R!N*\#"\*D&}o!!}oE:*\#"\*\*\!"\*\!E"\*w&*\*\!!e*\+)))))))))ʹ#*\&*X]!}oEʭ:*X]!R"X]!e*\+)))))))))*X]!*X]R!N*\#"\*\&}o*X]!}oE:*\#"\8*\&}2F*\"k*\+"iP!?\!}2D!*q!!N!*q!E͛! " !*q!!N!*q!E͛! " !?\: !ͩ!BD *B&}2B*B&́!A!P͛OE;*B&͛"ͺ: User  ;!}2D!"?!ͩ!AD *A&́!0!9͛OE'!~],! 4 ! "X]!~],! "V]*B&!:e.͢ =*q*7v'=!V!"m!V:ͣ!R*mEʵ>!V*mn&! Eʫ>!V*m! *mRò>*m#"mY>! *?!!V:p!p!Ef?͛ͺ& existiert, Ueberschreiben (J/N) ? !ͩ!AD*A&}2A*A&͛"*A&!JEO?!oc?!d7!! e. 5Al?!o!͒E?!}2D!_*q*7!sM"Direktory ist voll weiter mit  ! e. !`*q*7)))))!n&!N!`*q*7)))))!n&"k!}2F!}2E*F&}o*D&}o}oEA͡8*D&}oEA!p !!]o !!e*i!Nͺ!͒EA!Ͱ !͓MDiskette voll, *q*7v'=M wieder geloescht != !_*q*7!s!,7!! e. A!Ͱ .@! *o! e. !!fzcA"m!_*m!s*m#AA>!}2D+(! e. ͪ"ͣ7!!!ͩ!CD *C&TRB!_*q*7!s!*q!!N!*q!E͛!#" !],aIURhB!_*q*7!s!*q!!N!*q!E͛!:" !],aI R|B R†B!],aI RʚBR¤B!],aI RʸBRB!],aI RBRB!],aIRBRB!],aIDRiD|&!"m!}2D*m!*T]͸*D&}o}oEʶC*m#"mMSelect !]*m+))))):=M (J/N) ? = !ͩ!CD *C&}2C*C&͛" *C&!J}2DC! e. *D&EMD!]*m+))))):!G!]*m+)))))!n&!N!]*m+)))))!n&"k*k!3!5&*3*5!!ͨ2!"7!"q(:*!],aICR¬DMcopy *q*7v'=M to Drive=:  ! e. ͣ7aISRfGM Freier Diskspeicher auf Laufwerk !ͩ!AD *A&}2A*A&͛"ͺ:  *A&́!A!P͛OEcG!!{]"m!.*A&!AR"m!{]!+n&!!{]!+n&  !!{]!+n& ! !~]!~],͛!!yͺ KByte  !7!! e. aIRRvGͣ7aIFR%I*qv'M Filelaenge MS-DOS := !!`*q)))))!n& !!`*q)))))!n& !`*q)))))!n& !~]!~],͛!!yͺ Bytes ---> CP/M :  !~],! 4 !͈EH!~],! !~]H!~],! ! !~]͛!~],!&ͺ KByte  !7!! e. aIIR5I'aIWRaI!M MSWRITE.CHNp! aI*C&!XEʀA!! ͺ KByte  !7!! e. ~GIRI'-IWRW!M MSWRITE.CHNp! =I*1!d!Pp>úHP!!!͙͛! "!:!ͪ! " "*"! *+"͠*!}oEE!"""""!"**s**s**s#r**s#r**s#r!"~*R;"R;"R;" R;"R;"R;"R;"R;"R;"RP"!2!o&"~à" Rʂ"Rʂ"Rʂ"Rʂ"R”"!2!"~à"!2!*~"*! "g*g!0E"M'Ohne CP/M-Plus geht da leider nichts ! !o&"s*s!A}2B!*w&o&"g*g!͒Eb#M#MS-DOS-Laufwerk existiert nicht !? !*s! !o&"oMROOT!G"t!!*t!!k!"m"c}2e"f"h"j*h̀!'Eb$͛ͺ ^M auf Spur *h!&ͺ kann nicht zugegriffen werden. ͺ0Fehler beim Umsetzen Cluster in Spur und Sektor  !7!ä%! !*j!!k!"e!!*f*e^#V!k!"u! !*h!!k!"m! !*u!!k!"m! !*c!!k!"m!!!!!k!"m*e&E)%!!!!!k!"mC%! !!!!k!"m*m!͒E%M%Fehler bei DiskIO auf MS-DOS Diskette ! !*B&!AR!!k!"g!}21*w&!!!!eʹ#*w&!!!!e!ʹ#!e!n&!͒!e!n&!͒}oE&!}21"M"O"Q*Q!R"Q*Q!"Q*Q! "Q*Q!*Os#r*Q!E*Ms#r!!fzʦ&"m!*m͙*m#Ç&"9*9!!"/!e*/n&!!e*/!n&"-*9͋E'*-!V!}2;0'*-!|g}o!}2;*;&!"!!cfzl'"!*!ͧ&Ec'*#"*!#G'*"+*+}2r!rO~G#w*r&"r"r"r"r >M*rw>*r4!'(<  q+N# ( B(0 }*rw'R}*rw"r! t*r))):!!k!.e.=! t*r))):! !k=!r!r:! !͛ͺ<*** Ingenious Systems CP/M ---> MS-DOS Copy Utility ***  ! !͛ͺ6 from Andreas Buchelt Copyright (c) 1988 !!͛ͺVerzeichnis von Laufwerk *B&"!:" ͛ͺ User : *?!& !!͛ͺ! fuer Hilfe fuer Exit *=!FEʬ)*=";û)!F!R";!"r*r*;͸*r*7!R*=}oE*!*r!!N!*r!E! t*r)))!! s͛! t*r*7))):!!k!ͪ!."! t*r*7))):! !k!ͪ! " ! s*r*7n&E*͛!#" *͛!:" *r#"r)!F!R*=*7REʸ+!*r!!N!*r!E͛ͺ-------------- *r#"r*r!E!͒Eʸ+!*r!!N!*r!E͛ͺ  *r#"rP+l,}2r!*q!!N!*q!E*r&E ,͛!>" ,͛! " !*q!!N!*q!E*r&E_,͛!<" k,͛! " "r!ͼ+*q*r"q*=!E,M!Keine Datei in diesem Verzeichnis !7!! e. à-*q!E*-!"q*=!F!R*7!}oE*-!"q*7!R"7͓)*q*=EF-!"q!"7*7*q*=Ek-!"q!"7͓)*q*;Eʙ-*7!"7!F!R"q͓)!ͼ+!!fz-"m!*m͙*m#ì-!!͛ͺ& Befehlsverzeichnis fuer Version 1.4  !!͛ͺ)Bildschirm Befehle ! Disk Befehle  !! ͛ͺ-----------------------+---------------------- !! ͛ͺ)^X : naechste Datei ! N : neue CP/M-Disk !! ͛ͺ^E : Datei zurueck !  !! ͛ͺ)^D : naechste Spalte! S : Diskspace DOS  !! ͛ͺ)^S : Spalte zurueck ! I : DOS-Disk erase !!͛ͺ%Datei Befehle ! Copy verlassen !!͛ͺ-----------------------+---------------------- !!͛ͺT : Tag Datei !  !!͛ͺU : Untag Datei !  !!͛ͺC : copy Datei ! X : CP/M !!͛ͺ)G : Group copy ! R : lesen von DOS- !!͛ͺ&F : Dateigroesse ! Diskette !!͛ͺ zurueck mit beliebiger Taste !  !ͩ!CD ! }2C|&!!͙!!͙)͓)!͹+2!q"q"q*q"q*q"q! t*q*q!))): !q! t*q))):!q:E1*q#"qà1! t*q))):!q:E1*q+"q1*q*q͸Eʀ2! t*q))): !r! t*q)))! t*q))): ! t*q)))!r: *q#"q*q+"q*q*qEʠ1*q*qEʫ2*q*qT1*q*qE2*q*qT1q"!"=!q!*B&!@Rs!! fz3"m!q*m!?s*m#2! !#fzJ3"m!q*m!s*m#(3!!r!!qo&"m*m!͒E`4*=#"=! t!)))!! s!r! *m!! t!)))!! d!o&"m*m!͒EP4*=#"=! t*=)))!! s!r! *m!! t*=)))!! d*m!E3*=!E{4!*=T1Ò4IGS V1.3CPM-->MSDOS!}2DM@Achtung ! Alle Daten der DOS-Diskette gehen verloren. Ok (J/N) ? !ͩ!CD *C&}2C*C&͛" *C&!J͒E/5!}2D! e. 9!e!+)))))))))!!N!4!e!+)))))))))!!d!e!+)))))))))! !s!e!+)))))))))! !s!e!+)))))))))! !s!e!+)))))))))!!s!e!+)))))))))!!s!e!+)))))))))!!s!e!+)))))))))!!p&s!e!+)))))))))!!pl&s!e!+)))))))))!!&s!e!+)))))))))!!l&s!e!+)))))))))!!s!e!+)))))))))!!s!e!+)))))))))!!s!e!+)))))))))!! s!e!+)))))))))!!s!e!+)))))))))!!s!e!+)))))))))!!s!e!!s!e!!s!e!!s!e!!!N!e!+)))))))))!!N!!fzB8"q!e!+)))))))))*q!N!s*q#8! ͑#*w&!!!!e!+)))))))))ʹ#*w&!!!!eʹ#*w&!!!!e!ʹ#*w&!!!!eʹ#*w&!!!!e!ʹ#!"5*5"q!"q!!fzc9"q*q#"q*q*q!"q*q!E"q*w&*q*q!!e!+)))))))))ʹ#*q#8!e!+)))))))))! !N!4!e!+)))))))))! d!e!+)))))))))! !(s*w&!*5!!e!+)))))))))ʹ#! e. :"q*q"|q*|q!!"q!e*q!n&!N!e*qn&"~q*|q͋Es:*~q!V"|q*~q!|g}o"~qÕ:*~q!|g}o"|q*~q!|g}o"~q!e*q*~q!|g}os!e*q!*~q!Vs*|q!ͥE:"q!}2q!}2q*w&*q&*q&!!e!+)))))))))ʹ#!}2q!}2q!}2q*q&}oEu>!"q*q&#}2q!e!+)))))))))*qn&!!e!+)))))))))*qn&!}o}2q*q&*q&}o}oE;*q&"q*q&"q*q"q!}2q*q&}o!e!+)))))))))*q! n&́! !'͛O}oEʣ=!q!! s!e!+)))))))))*q!q!! d!q:! t*q*7))):!! k͍Eʣ=͛ͺ# existiert, ueberschreiben (J/N) ?  !ͩ!CD *C&}2C*C&͛" *C&!JEʙ=!e!+)))))))))*q!s!e!+)))))))))*q!n&!!e!+)))))))))*q!n&9*w&*q&*q&!!e!+)))))))))ʹ#ã=!}2DÖB!e!+)))))))))*qn&!*q&!o}o}2q*q! "q*q&*q!ͥ}oEK;*q&}oEr>*q&#}2q*q&*q&!}2q*q&!E}2q*w&*q&*q&!!e!+)))))))))ʹ#7;*q&E@B*q*q&͒*q*q&͒}oE>*w&*q*q!!e!+)))))))))ʹ#!! fz:?}2q!e!+)))))))))*q*q&! t*q*7)))*q&!n&s*q&#>!e!+)))))))))*q! ! s! !fzʨ?}2q!e!+)))))))))*q*q&!s*q&#k?!i!r!r!+)^#V!r!r!r͗'!r!+)^#V&v'}2r!r!+)^#Vl&v'}2r!e!+)))))))))*q!!*r&!Ns!e!+)))))))))*q!*r&!V*r&!Ns!e!+)))))))))*q!*r&*r&!Ns!e!+)))))))))*q!*r&!V*r&!PR!Ns!e!+)))))))))*q!*q&s!e!+)))))))))*q!*ql&s!e!+)))))))))*q!*!N!|g}os!e!+)))))))))*q!*!V!|g}os!e!+)))))))))*q!*! Vs!e!+)))))))))*q!!s*w&*q*q!!e!+)))))))))ʹ#ÖBMDirectory voll. Weiter mit ! s*q*7!s!}2D ! e. ÖBD"lq*lq^#V"`q*F&EB!*lqs#r]C*lq^#V#*lqs#r*lq^#Vͧ&*lq^#V!c}oEB*lq^#V!cE]C! s*q*7!sMDiskette voll ! weiter mit  !}2D!*lqs#r*`q!!V"9!e*9!n&!N!e*9n&"bq*`q͋EC*bq*lq^#V!N|g}o"bqC*bq*lq^#V|g}o"bq!e*9*bq!|g}os!e*9!*bq!Vs!"rq*͑#*rq*͸E E* !pq!nq&*w&*pq*nq!!e*rq+)))))))))ʹ#*rq#"rq*rq*͸ED*nq#"nq*pq*nq!"pq*nq!E"nq*w&*pq*nq!!e*rq+)))))))))ʹ#*rq#"rq*rq**&}oED!}2F! ͚B&DP!q!*q!!N!*q!E͛! " !*q!!N!*q!E͛! " !q: *B&!:e.͢ =*q*7'=!V!"m!V:ͣ!R*mE!F!V*mn&! EF!V*m! *mRF*m#"mE!!V:p!p !]"*!!6'EFM7Zu wenig Platz auf der MS-DOS Diskette. weiter mit  ! e. ! s*q*7!sùH!"m*m#"m*mͧ&*m!cͥ}oEF*m"k*m9*k" !}2F!}2!]"!"p*p*! !( *D&}o}oEBH!!(*p#*R"i*i!͸EʣG!!("iG!!(*iR"i!}2!p !!!(*po !!e*i; *i!E!E!H*i!"5H*i!!"͗B*p#"pG!͑#*w&!!!!eʹ#*w&!!!!e!ʹ#*w&!!!!eʹ#*w&!!!!e!ʹ#!!fzH"m! s*m!s*m#H>!}2Db(! e. ͪ"*s!A}2B*o"?)ͥ%*1&EIMkeine DOS Diskette !M3 Neue Disk, Disk Initialisieren oder Ende (N/I/E) ?= !ͩ!CD *C&}2C*C&́!E͑!I͑!N͑OEyI! e. *C&ERI IIRI|4I*1&}oEIQ1!"q!"7͓)!͹+!!!ͩ!CD *C&}2C*C&TR™J! s*q*7!s!*q!!N!*q!E͛!#" !͹+åPURJ! s*q*7!s!*q!!N!*q!E͛!:" !͹+åP RKRK!͹+åP R/K R9K!͹+åP RMKRWK!͹+åP RkKRuK!͹+åPRʉKR“K!͹+åPCRKMCopying *q*7'= E͔E! e. !͹+åPGRL!}2DMGroup-Copy to MS-DOS Disk E!d7!!"q!"7͓)*D&}o*q*=͸}oEL! s*qn&EʿL! s*q!s*q!F͸EʣL!*q!!N!*q!E͛!:" MCopying *q'= ͔E*q#"qL!"q!"7! e. ͓)!͹+åP/RL͡-åPNRN!}2D|&MDirectory von Laufwerk !ͩ!BD *B&}2B*B&́!A!P͛OEM*B&͛"ͺ: User  ÆM!}2D!"?!ͩ!AD *A&́!0!9͛OEM! *?*A&!0R"?M!}2D*A&͛" !ͩ!AD *A&́!0!9͛OE9N! *?*A&!0R"?RN*A&! ͒ERN!}2D*A&͛" *?!EzN!}2DÆN! *?*D&EʚN!A}2BàN)Q1͓)!"q!"7!͹+! e. åPIRN! e. E|4!͹+åPSRFO! e. E͛6'!&ͺ KByte frei auf MS-DOS Diskette !7!! e. !͹+åPFR}PM Dateilaenge : E*B&!:e.͢ =*q'=!V!"m!V:ͣ!R*mEO!V*mn&! EO!V*m! *mRO*m#"mÏO!!V:p!p !]"*!E!E3P*!"GP*!!"*͛!&ͺ KByte  !L7!! e. !͹+åPRR¥P!M MSREAD.CHNp! *C&!XE J!!! *o &ͺ KByte  ͫCopyrigRB *cBu"Video 88 Grafik-TermZC0X=;00H [2JE1LR1MTK(7m)0m~7#~= oͦkԄ!!"~#(}:$= +*!5!*!!:(2!5:(>2!!!:O::O:!*! !45(! +/ 0y0( d!k5!{5__o&  :(͠|(  *"x2y( >28!"9!! og2"">~22 9/4*9 Co&ͦͣ} [ (!e{ͦA8Q0G: x@!\w# (͂ ?(*( .( w^. ^!h6# (?( *( ͂( w#>?> w#ͦ 8 !ɿ .,;:=?*[]<>{}a~ |ʹ}ͽƐ'@'7||}>2ͯ*Bڨ  "og"2>2! """*B"[R0*"^#V#^#V#N#FO/o&9O/o&9!9(> (G!9 w#Eͺw}8' RB0 >' RqRR!+ Ͱ R!+ Ͱ r!+ Ͱ r!+ Ͱ r!# Ͱ r!+ Ͱ T]KB!z> S>))0 = | |̀̀DMgo>jB0 7?= H͒<z5a)a<z {0Gɯgo||~}||/g}/o#}o&K[xAJSJDM!b"!6J"DM'd } ) W _}8(8J`9{T]=o`9y ) >' ́ ͬ͗ }>' xˆ }} ˸T}ٕ(0D=z ,= ( ͒ 0%{ , 7 ?(8ͬ x ͆ - r 8˸x ͏  ,-xG}r }مM 9r .>#n0͒ { = - nx ͇ ,-(-˸G,-r }ٕ?M 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( ?}ٽ }ցr <(r 7{ = |٤g{٣_z٢Wy١Ox٠G{ ͬ ́ }x>' ͬ}ƀ/ƀo -́ }0͎-́ ͎,}l˸ 8 4 ͗ x( - 8́ - 8,́ }l8;*!͗ ! >4ͬ͗ ͗ ͬ--- ́ ,,,-xGg?+2n*8t z~,->' x' ͘}. ͆́ , ! >4,͢- o&0%,͗ }gr }؉}颋.:}8c~I$I~L*͢ٷx˸ }0G,<},-(-́ !>I0 ͗͘ o8 ͆ >' m.`1pF,t6|!wS<.z}[|%FXc~ur1}͆ٯx(<˸ 8 !~J 0.O!>s 8 =  n s͗ ͆ .n 0 ͎-́ OT0 j oD,:j !I}袋.}8c~I$I~L! >ͬ͗ I× nn ͗ = ͆ nf^VNF!DLT\I!!53!r1!͒!> x #-= o˸x͆(- }(x>8(z ,z `iÃ!>' |r |̀>)=|(DMbo˸88x(0 8> ̀x(>-{(ay( z(>. ( {>E>+|(|Dg>-|/ 0:p# ~# +>0w#,-  60#}˸}րogM| .(z = ~> x0w#xG%͇ %͇ ZJDM%͇ = _~65+~hìx-Sx9?+{Η@}|z z gZJDM0{ ,7}o˸? #yO!@9i&?  #?w#?/w#?w#!9! E9!!9~(+Fͺ!"9!(#>2*"| >"2:( Ͷ *w*6 !\$![ (ͦ( #:~CONTRMKBDLSTCAUXUSR>2i:*ˮ~0:*:(@q##pZ* :(  ~* < >26"!"""~>2""v>2>"!"ˮ(!~8>~O6~*"w(6(2(-()(6 (8 0 :(* y(~#+ (( 66 #6 #"*: y~o p .##~ͺ(.6w4._~ =*##55= *[R8*~#"= ͣ}== ͯ}͵}*#w+#~+>*~('k!0(ˮ]k!8ˮ!]~-#8~>27kˮw>O$6̃s #r$ͣ6̏ k ( (ˮ qk(ˮ ( k ˮ*O:~ ##~._q4((=ʦ==ʩ=ʬò*:4^q*##~6ͺ>2}*|(̓|( ̓6-#[RM8( G> A~#*'C! !TRUEFALSE!9N#Y~#( G~#> >    "~(kѻ(( !0 (ˮ!!>2Sz:0:*6##ww#w$w#w:  ##N#F*B>2w#w#[s#r> "~ͮ*-w#ww##> ͮÁ""~>2:ZR0 *4#4>2:ZR> *4 #4(> >22*f(/˦:G(##~++ :O x yC!ͺ Q*:G(##~._.͚f<\=<͚*##w ͮ +4 #4x >>2:G("ͮ"*nˮ*0 SZѷR8@* N#F#s#r, 0})jS\*##w+ N#FB ͮr+s>2!T]>)j)0 0= ]R!#]*^#V#N#F#^#V>2Ͱ:0:*6 #-Nw#Fwq#p#6#w#w#w"~Á>">!DM!":*B:!>(>2>">!"2"~ʰ*w#wx(9* :O *-4 #4!*4 #4 *-N#Fq#pV+^Bq#pSZѷR&* s#r$ s#rL <?*L!\  <( !\$>2>2L:>!(* \$\<(!3: [1ð\!(7"~> 2"S"Ns#FrB(Z#\: \<(?*"}K\! !*}#"}! x \* *>) 2""{_!"*nf}(HR0nf" ^VMDnfutqp*s#r*s#r"* uKB!0>' ~#fo{_"*R0RnfR0KqputsrNF( ^VNF^V*SutKqp R*R(~w~wnf ut"6#K*K*!""*NFy(* "*B0Cnf* [R*"*RS[s#r^#V""6#>O"w2x2*"!F"" &y*"*>2"*"!F"""!\*: Nr!~6go(\R*s#r_2x( s x(T]DMx(R0 U(͝O/o&9q# (!>F0#( ~ ( #]( ~ ( (#}(  i&T-a%â}ͦo*!~6o&|:2 2}:__zѯ2*|KB " z ^C User break+=  I/O Run-time error {ʹ, PC=*ͯNot enough memory Program aborted :ʎ'1!d!+>v'P!!!͙͛! "!:!ͪ! " "*"! *+"͠*!}oEE!"""""!"**s**s**s#r**s#r**s#r!"~*R;"R;"R;" R;"R;"R;"R;"R;"R;"RP"!2!o&"~à" Rʂ"Rʂ"Rʂ"Rʂ"R”"!2!"~à"!2!*~"*! "g*g!0E"M'Ohne CP/M-Plus geht da leider nichts ! !o&"s*s!A}2B!*w&o&"g*g!͒Eb#M#MS-DOS-Laufwerk existiert nicht !? !*s! !o&"oMROOT!G"t!!*t!!k!"m"c}2e"f"h"j*h̀!'Eb$͛ͺ ^M auf Spur *h!&ͺ kann nicht zugegriffen werden. ͺ0Fehler beim Umsetzen Cluster in Spur und Sektor  !7!ä%! !*j!!k!"e!!*f*e^#V!k!"u! !*h!!k!"m! !*u!!k!"m! !*c!!k!"m!!!!!k!"m*e&E)%!!!!!k!"mC%! !!!!k!"m*m!͒E%M%Fehler bei DiskIO auf MS-DOS Diskette ! !*B&!AR!!k!"g!}21*w&!!!!eʹ#*w&!!!!e!ʹ#!e!n&!͒!e!n&!͒}oE&!}21"M"O"Q*Q!R"Q*Q!"Q*Q! "Q*Q!*Os#r*Q!E*Ms#r!!fzʦ&"m!*m͙*m#Ç&"9*9!!"/!e*/n&!!e*/!n&"-*9͋E'*-!V!}2;0'*-!|g}o!}2;*;&!"!!cfzl'"!*!ͧ&Ec'*#"*!#G'*"+*+!}2w!Eʅ+>!!͛ͺ3MS-DOS Disketten unter CPM-plus lesen und schreiben !!͛ͺ3=================================================== ! ! ͛ͺMS-DOS Diskette in Laufwerk *w&!A"ͺ : einlegen. !! ͛ͺ#Disk-Parameter-Block fuer Laufwerk *w&!A"ͺ: muss  ͛ͺkorrekt gesetzt sein. !! ͛ͺ1Seitenumschaltung erfolgt ueber Sektorueberlauf ! ! !͛ͺLesen MS-Disk  ! !͛ͺSchreiben MS-Disk  ! !͛ͺDOS-Laufwerk wechseln  ! !͛ͺ#Exit ---> !ͩ!AD *A&}2A*A&!R*A&!W}o*A&!X}o*A&!C}oE)*A&RRp*!M MSREAD.CHNp! Â+WRœ*!M MSWRITE.CHNp! Â+CRu+!!͛ͺEnter new DOS-Drive :  !AD *A&}2A*A&!AR}2w!o&"s*s!A}2B!*w&o&"g!*s*g!͒Er+M#MS-DOS-Laufwerk existiert nicht !? Â+XR‚+ }' *s!A}2B!*w&o&"g!*s*g!͒EʒM#MS-DOS-Laufwerk existiert nicht !? ä*XRX