(*----------------------------------------------------------------------*)
(*        PIBFHIO.PAS --- File Handle Input/Output for Turbo Pascal     *)
(*----------------------------------------------------------------------*)
(*                                                                      *)
(*  Author:  Philip R. Burns                                            *)
(*  Version: 1.0  (June, 1985)                                          *)
(*                                                                      *)
(*  Systems: For MS-DOS on IBM PCs and close compatibles only.          *)
(*           Note:  I have checked these on Zenith 151s under           *)
(*                  MSDOS 2.1 and IBM PCs under PCDOS 2.0.              *)
(*                                                                      *)
(*  Needs:   Global types from GLOBTYPE.PAS.                            *)
(*                                                                      *)
(*  History: Original with me.                                          *)
(*                                                                      *)
(*           Suggestions for improvements or corrections are welcome.   *)
(*           Please leave messages on Gene Plantz's BBS (312) 882 4145  *)
(*           or Ron Fox's BBS (312) 940 6496.                           *)
(*                                                                      *)
(*           IF you use this code in your own programs, please be nice  *)
(*           and give proper credit.                                    *)
(*                                                                      *)
(*----------------------------------------------------------------------*)
(*                                                                      *)
(*  Usage:   These routines provide a Turbo Pascal interface to the     *)
(*           MS DOS file handle style input/output routines.  These are *)
(*           used in PibTerm for I/O during uploading and downloading,  *)
(*           as well as for copying files.  Use of these routines       *)
(*           allows precise control of file sizes and avoids various    *)
(*           bugs in the Turbo Block I/O routines.                      *)
(*                                                                      *)
(*----------------------------------------------------------------------*)
(*                                                                      *)
(*  Routines:                                                           *)
(*                                                                      *)
(*      Open_File_Handle                                                *)
(*      Close_File_Handle                                               *)
(*      Create_File_Handle                                              *)
(*      Read_File_Handle                                                *)
(*      Write_File_Handle                                               *)
(*                                                                      *)
(*----------------------------------------------------------------------*)

(*----------------------------------------------------------------------*)
(*                  Constants for file handle access                    *)
(*----------------------------------------------------------------------*)

CONST
   Access_Read_Mode           = 0;
   Access_Write_Mode          = 1;
   Access_Read_And_Write_Mode = 2;

   Attribute_None             = 0;
   Attribute_Read_Only        = 1;
   Attribute_Hidden           = 2;
   Attribute_System           = 4;
   Attribute_Volume_Label     = 8;
   Attribute_Subdirectory     = 16;
   Attribute_Archive          = 32;

(*----------------------------------------------------------------------*)
(*            Open_File_Handle --- Opens file using file handle         *)
(*----------------------------------------------------------------------*)

FUNCTION Open_File_Handle(     File_Name:   AnyStr;
                               File_Access: INTEGER;
                           VAR File_Handle: INTEGER ) : INTEGER;

(*----------------------------------------------------------------------*)
(*                                                                      *)
(*     Function:   Open_File_Handle                                     *)
(*                                                                      *)
(*     Purpose:    Opens file using file handle                         *)
(*                                                                      *)
(*     Calling Sequence:                                                *)
(*                                                                      *)
(*        Error := Open_File_Handle(     File_Name:   AnyStr;           *)
(*                                       File_Access: INTEGER;          *)
(*                                   VAR File_Handle: INTEGER ) :       *)
(*                                       INTEGER;                       *)
(*                                                                      *)
(*           File_Name   --- path name of file to be opened             *)
(*           File_Access --- mode to access file                        *)
(*                           0 = read only                              *)
(*                           1 = write only                             *)
(*                           2 = read and write                         *)
(*           File_Handle --- returned file handle                       *)
(*           Error       --- DOS error return code                      *)
(*                                                                      *)
(*     Calls:                                                           *)
(*                                                                      *)
(*        MsDos                                                         *)
(*                                                                      *)
(*----------------------------------------------------------------------*)

VAR
   Reg  : RegPack;

BEGIN (* Open_File_Handle *)
                                   (* Convert path name to Ascii Z string *)

   Convert_String_To_AsciiZ( File_Name );

                                   (* Set parameters for open file handle *)
   Reg.Al := File_Access;
   Reg.Ah := $3D;
   Reg.Ds := SEG( File_Name[1] );
   Reg.Dx := OFS( File_Name[1] );

                                   (* Open file, get handle *)
   MsDos( Reg );
                                   (* Check for bad return  *)

   IF ( Carry_Flag AND Reg.Flags ) = 0 THEN
      BEGIN
         Open_File_Handle := 0;
         File_Handle      := Reg.Ax;
      END
   ELSE
      BEGIN
         Open_File_Handle := Reg.Ax;
         File_Handle      := 0;
      END;

END   (* Open_File_Handle *);

(*----------------------------------------------------------------------*)
(*                Close_File_Handle --- Closes file handle              *)
(*----------------------------------------------------------------------*)

FUNCTION Close_File_Handle( File_Handle: INTEGER ) : INTEGER;

(*----------------------------------------------------------------------*)
(*                                                                      *)
(*     Function:   Close_File_Handle                                    *)
(*                                                                      *)
(*     Purpose:    Closes file handle                                   *)
(*                                                                      *)
(*     Calling Sequence:                                                *)
(*                                                                      *)
(*        Error := Close_File_Handle( File_Handle: INTEGER ): INTEGER;  *)
(*                                                                      *)
(*           File_Handle --- File handle of file to close               *)
(*           Error       --- DOS error return code                      *)
(*                                                                      *)
(*     Calls:                                                           *)
(*                                                                      *)
(*        MsDos                                                         *)
(*                                                                      *)
(*----------------------------------------------------------------------*)

VAR
   Reg  : RegPack;

BEGIN (* Close_File_Handle *)

                                   (* Set parameters for close file handle *)
   Reg.Ah := $3E;
   Reg.Bx := File_Handle;
                                   (* Close the file handle *)
   MsDos( Reg );
                                   (* Check for bad return  *)

   IF ( Carry_Flag AND Reg.Flags ) = 0 THEN
      Close_File_Handle := 0
   ELSE
      Close_File_Handle := Reg.Ax;

END   (* Close_File_Handle *);

(*----------------------------------------------------------------------*)
(*           Read_File_Handle --- Performs read using file handle       *)
(*----------------------------------------------------------------------*)

FUNCTION Read_File_Handle(     File_Handle: INTEGER;
                           VAR File_Buffer  ;
                           VAR Read_Length: INTEGER ) : INTEGER;

(*----------------------------------------------------------------------*)
(*                                                                      *)
(*     Function:   Read_File_Handle                                     *)
(*                                                                      *)
(*     Purpose:    Reads file using file handle                         *)
(*                                                                      *)
(*     Calling Sequence:                                                *)
(*                                                                      *)
(*        Error := Read_File_Handle(     File_Handle: INTEGER;          *)
(*                                   VAR File_Buffer  ;                 *)
(*                                   VAR Read_Length: INTEGER ) :       *)
(*                                           INTEGER;                   *)
(*                                                                      *)
(*           File_Handle --- File handle of file to read                *)
(*           File_Buffer --- Buffer area to receive data read           *)
(*           Read_Length --- On input, is number of characters to read. *)
(*                           On output, is number of chars actually     *)
(*                           read                                       *)
(*           Error       --- DOS error return code                      *)
(*                                                                      *)
(*     Calls:                                                           *)
(*                                                                      *)
(*        MsDos                                                         *)
(*                                                                      *)
(*----------------------------------------------------------------------*)

VAR
   Reg  : RegPack;

BEGIN (* Read_File_Handle *)
                                   (* Set parameters for read *)
   WITH Reg DO
      BEGIN

         Ah := $3F;
         Bx := File_Handle;
         Cx := Read_Length;
         Ds := SEG( File_Buffer );
         Dx := OFS( File_Buffer );

      END;
                                   (* Perform the read *)
   MsDos( Reg );
                                   (* Check for bad return  *)

   IF ( Carry_Flag AND Reg.Flags ) = 0 THEN
      BEGIN
         Read_File_Handle := 0;
         Read_Length      := Reg.Ax;
      END
   ELSE
      BEGIN
         Read_File_Handle := Reg.Ax;
         Read_Length      := 0;
      END;

END   (* Read_File_Handle *);

(*----------------------------------------------------------------------*)
(*          Write_File_Handle --- Performs read using file handle       *)
(*----------------------------------------------------------------------*)

FUNCTION Write_File_Handle(     File_Handle: INTEGER;
                            VAR File_Buffer  ;
                            VAR Write_Length: INTEGER ) : INTEGER;

(*----------------------------------------------------------------------*)
(*                                                                      *)
(*     Function:   Write_File_Handle                                    *)
(*                                                                      *)
(*     Purpose:    Writes file using file handle                        *)
(*                                                                      *)
(*     Calling Sequence:                                                *)
(*                                                                      *)
(*        Error := Write_File_Handle(     File_Handle: INTEGER;         *)
(*                                    VAR File_Buffer ;                 *)
(*                                    VAR Write_Length: INTEGER ):      *)
(*                                            INTEGER;                  *)
(*                                                                      *)
(*           File_Handle  --- File handle of file to write              *)
(*           File_Buffer  --- Buffer area from which to write data      *)
(*           Write_Length --- On input, is number of chars. to write.   *)
(*                            On output, is number of chars actually    *)
(*                            written.                                  *)
(*           Error        --- DOS error return code                     *)
(*                                                                      *)
(*     Calls:                                                           *)
(*                                                                      *)
(*        MsDos                                                         *)
(*                                                                      *)
(*----------------------------------------------------------------------*)

VAR
   Reg  : RegPack;

BEGIN (* Write_File_Handle *)
                                   (* Set parameters for write *)
   WITH Reg DO
      BEGIN

         Ah := $40;
         Bx := File_Handle;
         Cx := Write_Length;
         Ds := SEG( File_Buffer );
         Dx := OFS( File_Buffer );

      END;
                                   (* Perform the read *)
   MsDos( Reg );
                                   (* Check for bad return  *)

   IF ( Carry_Flag AND Reg.Flags ) = 0 THEN
      BEGIN
         Write_File_Handle := 0;
         Write_Length      := Reg.Ax;
      END
   ELSE
      BEGIN
         Write_File_Handle := Reg.Ax;
         Write_Length      := 0;
      END;

END   (* Write_File_Handle *);

(*----------------------------------------------------------------------*)
(*          Create_File_Handle --- Creates file and file handle         *)
(*----------------------------------------------------------------------*)

FUNCTION Create_File_Handle(     File_Name:   AnyStr;
                                 File_Attrib: INTEGER;
                             VAR File_Handle: INTEGER ) : INTEGER;

(*----------------------------------------------------------------------*)
(*                                                                      *)
(*     Function:   Create_File_Handle                                   *)
(*                                                                      *)
(*     Purpose:    Creates file and file handle                         *)
(*                                                                      *)
(*     Calling Sequence:                                                *)
(*                                                                      *)
(*        Error := Create_File_Handle(     File_Name:   AnyStr;         *)
(*                                         File_Attrib: INTEGER;        *)
(*                                     VAR File_Handle: INTEGER ) :     *)
(*                                             INTEGER;                 *)
(*                                                                      *)
(*           File_Name   --- path name of file to be created            *)
(*           File_Attrib --- attributes for file:                       *)
(*                           None          = 0;                         *)
(*                           Read_Only     = 1;                         *)
(*                           Hidden        = 2;                         *)
(*                           System        = 4;                         *)
(*                           Volume_Label  = 8;                         *)
(*                           Subdirectory  = 16;                        *)
(*                           Archive       = 32;                        *)
(*           File_Handle --- returned file handle                       *)
(*           Error       --- DOS error return code                      *)
(*                                                                      *)
(*     Calls:                                                           *)
(*                                                                      *)
(*        MsDos                                                         *)
(*                                                                      *)
(*----------------------------------------------------------------------*)

VAR
   Reg  : RegPack;

BEGIN (* Create_File_Handle *)
                                   (* Convert path name to Ascii Z string *)

   Convert_String_To_AsciiZ( File_Name );

                                   (* Set parameters for create file handle *)
   Reg.Cx := File_Attrib;
   Reg.Ah := $3C;
   Reg.Ds := SEG( File_Name[1] );
   Reg.Dx := OFS( File_Name[1] );

                                   (* Open file, get handle *)
   MsDos( Reg );
                                   (* Check for bad return  *)

   IF ( Carry_Flag AND Reg.Flags ) = 0 THEN
      BEGIN
         Create_File_Handle := 0;
         File_Handle        := Reg.Ax;
      END
   ELSE
      BEGIN
         Create_File_Handle := Reg.Ax;
         File_Handle        := 0;
      END;

END   (* Create_File_Handle *);
