
(**********************************************************************)
(*                                                                    *)
(* Ph”niX SoftCrew  Turbo Pascal Programme                            *)
(* most (c) by PSC Software Development Lippstadt/Warendorf           *)
(*                                                                    *)
(* Ph”niX SoftCrew          ####   ####  ####                         *)
(* c/o Carsten Strotmann    #   # ##    ##                            *)
(* An der Kreutzbrede 20    ####   ###  ##     Software Development   *)
(*                          #        ## ##                            *)
(* 4410 Warendorf 1         #     ####   ####                         *)
(*                                                                    *)
(**********************************************************************)

(*

  Programmname   :ATARI Kompatibilit„ts Unit
  Filename       :A_UNIT.PAS
  von            :Carsten Strotmann
  letzte Žnderung:06.02.91
  Bemerkung      :

*)

UNIT A_UNIT;

INTERFACE

USES DOS, CRT;

TYPE
  a_sector = RECORD
             CASE INTEGER OF
              1 : ( secdata  : ARRAY [0..252] OF BYTE; { Sektordaten }
                    seclink  : WORD;                   { Link Word }
                    secsize  : BYTE;                   { Anzahl Bytes }
                    dummy    : WORD;
                  );
              2 : ( sectordat: ARRAY [0..$FF] OF BYTE );
             END;

  drivetab = RECORD
              steptime : BYTE; { Schrittzeit }
              dmamode  : BYTE; { DMA Modus }
              motorwait: BYTE; { Motor Nachlaufzeit }
              secbyte  : BYTE; { Bytes pro Sektor }
              sectrack : BYTE; { Max. Anzahl Sek. pro Track }
              secspace1: BYTE; { Zeit zwischen Sektoren }
              notused  : BYTE; { unbenutzt }
              secspace2: BYTE; { Freiraum zwischen Sektoren }
              fillcode : BYTE; { ASCII Code zum fllen }
              endtime  : BYTE; { Ruhezeit zum Ausschwingen }
              starttime: BYTE; { Anlaufzeit des Motors }
            END;

  filename = RECORD
               name    : ARRAY [0..7] OF CHAR; { Bezeichnung }
               ext     : ARRAY [0..2] OF CHAR; { Extender }
             END;

  direntry = RECORD
               flag    : BYTE;                 { Statusflag }
               length  : WORD;                 { L„nge des Files }
               startsec: WORD;                 { Startsector }
               name    : ARRAY [0..7] OF CHAR; { Bezeichner }
               ext     : ARRAY [0..2] OF CHAR; { Extender }
             END;

  vtoc     = RECORD
               version : BYTE;                   { Dos Version kompat. }
               maxfree : WORD;                   { Max. Sektoren der Disk }
               freesec : WORD;                   { Freie Sektoren }
               table   : ARRAY [0..$FF] OF BYTE; { Sektorenbelegungstabelle }
             END;

VAR
  olddrivetab : POINTER;
  { Zeiger auf alte Tabelle }

  a_drivetab  : drivetab;
  { Neue Laufwerkstabelle }

  a_vtoc      : vtoc;
  { VOLUME TABLE OF CONTENTS }

  a_dir       : ARRAY [1..64] OF direntry;
  { DIRECTORY ARRAY }

  dir_read,
  { Flag fr Directory schon gelesen }

  vtoc_read   : BOOLEAN;
  { Flag fr VTOC schon gelesen }

  secprotrk,
  { Sektoren pro Track }
  secsize,
  { Sektorengr”áe }
  diskside,
  { Diskettenseite }
  drivenum,
  { Laufwerksnummer }
  entrycount,
  { Eintragsnummer }
  a_error     : BYTE;
  { Fehlernummer }

FUNCTION DiskStatus : BYTE;
{ Ermittelt den Diskstatus }

PROCEDURE DiskReset;
{ Fhrt einen Diskreset aus }

PROCEDURE SetDrive (drive, value : BYTE);
{ Setzt Formatangaben fr Diskettenlaufwerk }

PROCEDURE SetNewDriveTab (strack, sbyte : BYTE);
{ Installiert neue Laufwerkstabelle }

PROCEDURE SetOldDriveTab;
{ Restauriert alte Laufwerkstabelle }

FUNCTION  Read_A_Sector (drive, side : BYTE; num : WORD; VAR buffer : a_sector): BYTE;
{ Liest einen ATARI Sektor }

FUNCTION  Write_A_Sector (drive, side : BYTE; num : WORD; VAR buffer : a_sector): BYTE;
{ Schreibt einen ATARI Sektor }

PROCEDURE Read_Dir (drive : BYTE);
{ Liest Directory ein }

PROCEDURE Read_VTOC (drive : BYTE);
{ Liest VTOC ein }

FUNCTION A_FindFirst (filen : STRING) : BYTE;
{ Findet ersten Filenamen in Directory und liefert Eintragsnummer zurck }

FUNCTION A_FindNext (filen : STRING): BYTE;
{ Findet n„chsten Filenamen in Directory und gibt Eintragsnummer zurck }

IMPLEMENTATION

FUNCTION DiskStatus : BYTE;
VAR
  reg : REGISTERS;
BEGIN
  reg.ah := 1;
  Intr ($13,reg);
  DiskStatus := reg.ah;
END;

PROCEDURE DiskReset;
VAR
  reg : REGISTERS;
BEGIN
  reg.ah := 0;
  Intr ($13,reg);
END;

PROCEDURE SetDrive (drive, value : BYTE);
VAR
  reg : REGISTERS;
BEGIN
  reg.ah := $17;
  reg.dl := drive;
  reg.al := value;
  Intr($13,reg);
END;

PROCEDURE SetNewDriveTab (strack, sbyte : BYTE);
BEGIN
  WITH a_drivetab DO
  BEGIN
    steptime := $DF;
    dmamode  := 2;
    motorwait:= $24;
    secbyte  := sbyte;
    sectrack := strack;
    secspace1:= $1B;
    notused  := $FF;
    secspace2:= $10;
    fillcode := $FF;
    endtime  := $F;
    starttime:= 8;
  END;

  GetIntVec ($1E, olddrivetab);
  SetIntVec ($1E, @a_drivetab);

END;

PROCEDURE SetOldDriveTab;
BEGIN
  SetIntVec ($1E, olddrivetab);
END;

FUNCTION Read_A_Sector (drive, side : BYTE; num : WORD; VAR buffer : a_sector): BYTE;
VAR
  reg : REGISTERS;
  track,
  sec,
  bb  : WORD;
  buf : ARRAY [0..$110] OF BYTE;

BEGIN
  IF (num > 0) AND (num < 720) THEN
  BEGIN
    bb := DiskStatus;

    IF bb > 0 THEN
      DiskReset;

    track := num DIV secprotrk;
    sec:= num - (track * secprotrk);
    IF sec = 0 THEN
    BEGIN
      sec := secprotrk;
      Dec (track);
    END;
    reg.ah := 2;        {Sektor lesen}
    reg.al := 1;        {Anzahl der Sektoren}
    reg.dh := side;     {Diskettenseite}
    reg.dl := drive;    {Laufwerk}
    reg.cl := sec;      {erster Sektor}
    reg.ch := track;    {Track des Sektors}
    reg.es := Seg(buf[0]);
    reg.bx := Ofs(buf[0]);
    Intr ($13,reg);

    Read_A_Sector := reg.ah;

    Move (buf,buffer,$100);

    FOR bb := 0 TO $100 DO
      buffer.sectordat[bb] := buffer.sectordat[bb] XOR $FF;
  END;
END;

FUNCTION Write_A_Sector (drive, side : BYTE; num : WORD; VAR buffer : a_sector): BYTE;
VAR
  reg : REGISTERS;
  track,
  sec,
  bb  : WORD;
  buf : ARRAY [0..$110] OF BYTE;

BEGIN
  FOR bb := 0 TO $100 DO
    buffer.sectordat[bb] := buffer.sectordat[bb] XOR $FF;

  Move (buffer,buf,$100);

  IF (num > 0) AND (num < 720) THEN
  BEGIN
    bb := DiskStatus;

    IF bb > 0 THEN
      DiskReset;

    track := num DIV secprotrk;
    sec:= num - (track * secprotrk);
    IF sec = 0 THEN
    BEGIN
      sec := secprotrk;
      Dec (track);
    END;
    reg.ah := 3;        {Sektor schreiben}
    reg.al := 1;        {Anzahl der Sektoren}
    reg.dh := side;     {Diskettenseite}
    reg.dl := drive;    {Laufwerk}
    reg.cl := sec;      {erster Sektor}
    reg.ch := track;    {Track des Sektors}
    reg.es := Seg(buf[0]);
    reg.bx := Ofs(buf[0]);
    Intr ($13,reg);

    Write_A_Sector := reg.ah;

  END;
END;

PROCEDURE Read_Dir (drive : BYTE);
VAR
 u : WORD;
 s : a_sector;

BEGIN
 a_error := 0;
 FOR u := 1 TO 8 DO
 BEGIN
   a_error := Read_A_Sector (drive,diskside,u+360,s);
   Move (s,a_dir[(u-1)*8+1],128);
   IF a_error > 0 THEN
     EXIT;
 END;
 dir_read := TRUE;
 entrycount := 0;
END;

PROCEDURE Read_VTOC (drive : BYTE);
VAR
  s : a_sector;
BEGIN
  a_error := 0;
  a_error := Read_A_Sector (drive,diskside,360,s);
  Move (s,a_vtoc,$80);
  vtoc_read := TRUE;
END;

FUNCTION A_FindNext (filen : STRING): BYTE;
VAR
  u,p : BYTE;
  f : BOOLEAN;
  fn,
  fs : filename;

BEGIN
  FillChar (fn,11,0);

  p := Pos('.',filen);

  FOR u := 1 TO p-1 DO
    fn.name[u-1] := filen[u];

  FOR u := p+1 TO Length(filen) DO
    fn.ext[u-p-1] := filen[u];

  f := FALSE;
 
  FOR u := 0 TO 7 DO
  BEGIN
    IF fn.name[u] = '*' THEN
      f := TRUE;
    IF f THEN
      fn.name[u] := '?';
  END;

  f := FALSE;

  FOR u := 0 TO 2 DO
  BEGIN
    IF fn.ext[u] = '*' THEN
      f := TRUE;
    IF f THEN
      fn.ext[u] := '?';
  END;

  FOR u := 0 TO 7 DO
    IF fn.name[u] = #0 THEN
      fn.name[u] := #32;

  FOR u := 0 TO 7 DO
    IF fn.ext[u] = #0 THEN
      fn.ext[u] := #32;

  REPEAT
    Inc (entrycount);

    FOR u := 0 TO 7 DO
      fs.name[u] := a_dir[entrycount].name[u];

    FOR u := 0 TO 2 DO
      fs.ext[u] := a_dir[entrycount].ext[u];

     FOR u := 0 TO 7 DO
       IF fn.name[u] = '?' THEN
         fs.name[u] := '?';

     FOR u := 0 TO 2 DO
       IF fn.ext[u] = '?' THEN
         fs.ext[u] := '?';

     IF a_dir[entrycount].flag = 0 THEN
       entrycount := $41;

  UNTIL (fs.name = fn.name) AND (fs.ext = fn.ext) AND (a_dir[entrycount].flag AND $80 = 0) OR (entrycount > $40);

  IF NOT (entrycount > $40) THEN
    A_FindNext := entrycount
  ELSE
    A_FindNext := 0;

END;

FUNCTION A_FindFirst (filen : STRING) : BYTE;

BEGIN
  entrycount := 0;
  A_FindFirst := A_FindNext (filen);
END;

BEGIN
  dir_read := FALSE;
  vtoc_read := FALSE;
  secprotrk := 18;
  secsize := 1;
  diskside := 0;
  drivenum := 0;
  entrycount := 0;
  a_error := 0;
END.