home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / s-fileio.adb < prev    next >
Text File  |  2000-07-19  |  30KB  |  1,000 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUN-TIME COMPONENTS                         --
  4. --                                                                          --
  5. --                       S Y S T E M . F I L E _ I O                        --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.53 $
  10. --                                                                          --
  11. --          Copyright (C) 1992-2000 Free Software Foundation, Inc.          --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNAT was originally developed  by the GNAT team at  New York University. --
  32. -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
  33. --                                                                          --
  34. ------------------------------------------------------------------------------
  35.  
  36. with Ada.Finalization;            use Ada.Finalization;
  37. with Ada.IO_Exceptions;           use Ada.IO_Exceptions;
  38. with Interfaces.C_Streams;        use Interfaces.C_Streams;
  39. with System.Soft_Links;
  40. with Unchecked_Deallocation;
  41.  
  42. package body System.File_IO is
  43.  
  44.    use System.File_Control_Block;
  45.  
  46.    package SSL renames System.Soft_Links;
  47.  
  48.    ----------------------
  49.    -- Global Variables --
  50.    ----------------------
  51.  
  52.    Open_Files : AFCB_Ptr;
  53.    --  This points to a list of AFCB's for all open files. This is a doubly
  54.    --  linked list, with the Prev pointer of the first entry, and the Next
  55.    --  pointer of the last entry containing null.
  56.  
  57.    type Temp_File_Record;
  58.    type Temp_File_Record_Ptr is access all Temp_File_Record;
  59.  
  60.    type Temp_File_Record is record
  61.       Name : String (1 .. L_tmpnam + 1);
  62.       Next : Temp_File_Record_Ptr;
  63.    end record;
  64.    --  One of these is allocated for each temporary file created
  65.  
  66.    Temp_Files : Temp_File_Record_Ptr;
  67.    --  Points to list of names of temporary files
  68.  
  69.    type File_IO_Clean_Up_Type is new Controlled with null record;
  70.    --  The closing of all open files and deletion of temporary files is an
  71.    --  action which takes place at the end of execution of the main program.
  72.    --  This action can be implemented using a library level object which
  73.    --  gets finalized at the end of the main program execution. The above is
  74.    --  a controlled type introduced for this purpose.
  75.  
  76.    procedure Finalize (V : in out File_IO_Clean_Up_Type);
  77.    --  This is the finalize operation that is used to do the cleanup.
  78.  
  79.    File_IO_Clean_Up_Object : File_IO_Clean_Up_Type;
  80.    --  This is the single object of the type that triggers the finalization
  81.    --  call. Since it is at the library level, this happens just before the
  82.    --  environment task is finalized.
  83.  
  84.    text_translation_required : Boolean;
  85.    pragma Import (C, text_translation_required, "text_translation_required");
  86.    --  If true, add appropriate suffix to control string for Open.
  87.  
  88.    -----------------------
  89.    -- Local Subprograms --
  90.    -----------------------
  91.  
  92.    procedure Free_String is new Unchecked_Deallocation (String, Pstring);
  93.  
  94.    subtype Fopen_String is String (1 .. 4);
  95.    --  Holds open string (longest is "w+b" & nul)
  96.  
  97.    procedure Fopen_Mode
  98.      (Mode    : File_Mode;
  99.       Text    : Boolean;
  100.       Creat   : Boolean;
  101.       Amethod : Character;
  102.       Fopstr  : out Fopen_String);
  103.    --  Determines proper open mode for a file to be opened in the given
  104.    --  Ada mode. Text is true for a text file and false otherwise, and
  105.    --  Creat is true for a create call, and False for an open call. The
  106.    --  value stored in Fopstr is a nul-terminated string suitable for a
  107.    --  call to fopen or freopen. Amethod is the character designating
  108.    --  the access method from the Access_Method field of the FCB.
  109.  
  110.    ---------------------
  111.    -- Check_File_Open --
  112.    ---------------------
  113.  
  114.    procedure Check_File_Open (File : AFCB_Ptr) is
  115.    begin
  116.       if File = null then
  117.          raise Status_Error;
  118.       end if;
  119.    end Check_File_Open;
  120.  
  121.    ----------------
  122.    -- Append_Set --
  123.    ----------------
  124.  
  125.    procedure Append_Set (File : AFCB_Ptr) is
  126.    begin
  127.       if File.Mode = Append_File then
  128.          if fseek (File.Stream, 0, SEEK_END) /= 0 then
  129.             raise Device_Error;
  130.          end if;
  131.       end if;
  132.    end Append_Set;
  133.  
  134.    ----------------
  135.    -- Chain_File --
  136.    ----------------
  137.  
  138.    procedure Chain_File (File : AFCB_Ptr) is
  139.    begin
  140.       File.Next := Open_Files;
  141.       File.Prev := null;
  142.       Open_Files := File;
  143.  
  144.       if File.Next /= null then
  145.          File.Next.Prev := File;
  146.       end if;
  147.    end Chain_File;
  148.  
  149.    -----------------------
  150.    -- Check_Read_Status --
  151.    -----------------------
  152.  
  153.    procedure Check_Read_Status (File : AFCB_Ptr) is
  154.    begin
  155.       if File = null then
  156.          raise Status_Error;
  157.       elsif File.Mode > Inout_File then
  158.          raise Mode_Error;
  159.       end if;
  160.    end Check_Read_Status;
  161.  
  162.    ------------------------
  163.    -- Check_Write_Status --
  164.    ------------------------
  165.  
  166.    procedure Check_Write_Status (File : AFCB_Ptr) is
  167.    begin
  168.       if File = null then
  169.          raise Status_Error;
  170.       elsif File.Mode = In_File then
  171.          raise Mode_Error;
  172.       end if;
  173.    end Check_Write_Status;
  174.  
  175.    -----------
  176.    -- Close --
  177.    -----------
  178.  
  179.    procedure Close (File : in out AFCB_Ptr) is
  180.       Close_Status : int := 0;
  181.       Dup_Strm     : Boolean := False;
  182.  
  183.    begin
  184.       Check_File_Open (File);
  185.       AFCB_Close (File);
  186.  
  187.       --  Sever the association between the given file and its associated
  188.       --  external file. The given file is left closed. Do not perform system
  189.       --  closes on the standard input, output and error files and also do
  190.       --  not attempt to close a stream that does not exist (signalled by a
  191.       --  null stream value -- happens in some error situations).
  192.  
  193.       if not File.Is_System_File
  194.         and then File.Stream /= NULL_Stream
  195.       then
  196.          --  Do not do an fclose if this is a shared file and there is
  197.          --  at least one other instance of the stream that is open.
  198.  
  199.          if File.Shared_Status = Yes then
  200.             declare
  201.                P   : AFCB_Ptr;
  202.  
  203.             begin
  204.                P := Open_Files;
  205.                while P /= null loop
  206.                   if P /= File
  207.                     and then File.Stream = P.Stream
  208.                   then
  209.                      Dup_Strm := True;
  210.                      exit;
  211.                   end if;
  212.  
  213.                   P := P.Next;
  214.                end loop;
  215.             end;
  216.          end if;
  217.  
  218.          --  Do the fclose unless this was a duplicate in the shared case
  219.  
  220.          if not Dup_Strm then
  221.             Close_Status := fclose (File.Stream);
  222.          end if;
  223.       end if;
  224.  
  225.       --  Dechain file from list of open files and then free the storage
  226.       --  Since this is a global data structure, we have to protect against
  227.       --  multiple tasks attempting to access this list.
  228.  
  229.       --  Note that we do not use an exception handler to unlock here since
  230.       --  no exception can occur inside the lock/unlock pair.
  231.  
  232.       SSL.Lock_Task.all;
  233.  
  234.       if File.Prev = null then
  235.          Open_Files := File.Next;
  236.       else
  237.          File.Prev.Next := File.Next;
  238.       end if;
  239.  
  240.       if File.Next /= null then
  241.          File.Next.Prev := File.Prev;
  242.       end if;
  243.  
  244.       SSL.Unlock_Task.all;
  245.  
  246.       --  Deallocate some parts of the file structure that were kept in heap
  247.       --  storage with the exception of system files (standard input, output
  248.       --  and error) since they had some information allocated in the stack.
  249.  
  250.       if not File.Is_System_File then
  251.          Free_String (File.Name);
  252.          Free_String (File.Form);
  253.          AFCB_Free (File);
  254.       end if;
  255.  
  256.       File := null;
  257.  
  258.       if Close_Status /= 0 then
  259.          raise Device_Error;
  260.       end if;
  261.    end Close;
  262.  
  263.    ------------
  264.    -- Delete --
  265.    ------------
  266.  
  267.    procedure Delete (File : in out AFCB_Ptr) is
  268.    begin
  269.       Check_File_Open (File);
  270.  
  271.       if not File.Is_Regular_File then
  272.          raise Use_Error;
  273.       end if;
  274.  
  275.       declare
  276.          Filename : aliased constant String := File.Name.all;
  277.  
  278.       begin
  279.          Close (File);
  280.  
  281.          if unlink (Filename'Address) = -1 then
  282.             raise Use_Error;
  283.          end if;
  284.       end;
  285.    end Delete;
  286.  
  287.    -----------------
  288.    -- End_Of_File --
  289.    -----------------
  290.  
  291.    function End_Of_File (File : AFCB_Ptr) return Boolean is
  292.    begin
  293.       Check_File_Open (File);
  294.  
  295.       if feof (File.Stream) /= 0 then
  296.          return True;
  297.  
  298.       else
  299.          Check_Read_Status (File);
  300.  
  301.          if ungetc (fgetc (File.Stream), File.Stream) = EOF then
  302.             clearerr (File.Stream);
  303.             return True;
  304.          else
  305.             return False;
  306.          end if;
  307.       end if;
  308.    end End_Of_File;
  309.  
  310.    --------------
  311.    -- Finalize --
  312.    --------------
  313.  
  314.    --  Note: we do not need to worry about locking against multiple task
  315.    --  access in this routine, since it is called only from the environment
  316.    --  task just before terminating execution.
  317.  
  318.    procedure Finalize (V : in out File_IO_Clean_Up_Type) is
  319.       Discard : int;
  320.       Fptr1   : AFCB_Ptr;
  321.       Fptr2   : AFCB_Ptr;
  322.    begin
  323.       --  First close all open files (the slightly complex form of this loop
  324.       --  is required because Close as a side effect nulls out its argument)
  325.  
  326.       Fptr1 := Open_Files;
  327.       while Fptr1 /= null loop
  328.          Fptr2 := Fptr1.Next;
  329.          Close (Fptr1);
  330.          Fptr1 := Fptr2;
  331.       end loop;
  332.  
  333.       --  Now unlink all temporary files. We do not bother to free the
  334.       --  blocks because we are just about to terminate the program. We
  335.       --  also ignore any errors while attempting these unlink operations.
  336.  
  337.       while Temp_Files /= null loop
  338.          Discard := unlink (Temp_Files.Name'Address);
  339.          Temp_Files := Temp_Files.Next;
  340.       end loop;
  341.  
  342.    end Finalize;
  343.  
  344.    -----------
  345.    -- Flush --
  346.    -----------
  347.  
  348.    procedure Flush (File : AFCB_Ptr) is
  349.    begin
  350.       Check_Write_Status (File);
  351.  
  352.       if fflush (File.Stream) = 0 then
  353.          return;
  354.       else
  355.          raise Device_Error;
  356.       end if;
  357.    end Flush;
  358.  
  359.    ----------------
  360.    -- Fopen_Mode --
  361.    ----------------
  362.  
  363.    --  The fopen mode to be used is shown by the following table:
  364.  
  365.    --                                     OPEN         CREATE
  366.    --     Append_File                     "r+"           "w+"
  367.    --     In_File                         "r"            "w+"
  368.    --     Out_File (Direct_IO)            "r+"           "w"
  369.    --     Out_File (all others)           "w"            "w"
  370.    --     Inout_File                      "r+"           "w+"
  371.  
  372.    --  Note: we do not use "a" or "a+" for Append_File, since this would not
  373.    --  work in the case of stream files, where even if in append file mode,
  374.    --  you can reset to earlier points in the file. The caller must use the
  375.    --  Append_Set routine to deal with the necessary positioning.
  376.  
  377.    --  Note: in several cases, the fopen mode used allows reading and
  378.    --  writing, but the setting of the Ada mode is more restrictive. For
  379.    --  instance, Create in In_File mode uses "w+" which allows writing,
  380.    --  but the Ada mode In_File will cause any write operations to be
  381.    --  rejected with Mode_Error in any case.
  382.  
  383.    --  Note: for the Out_File/Open cases for other than the Direct_IO case,
  384.    --  an initial call will be made by the caller to first open the file in
  385.    --  "r" mode to be sure that it exists. The real open, in "w" mode, will
  386.    --  then destroy this file. This is peculiar, but that's what Ada semantics
  387.    --  require and the ACVT tests insist on!
  388.  
  389.    --  If text file translation is required, then either b or t is
  390.    --  added to the mode, depending on the setting of Text.
  391.  
  392.    procedure Fopen_Mode
  393.      (Mode    : File_Mode;
  394.       Text    : Boolean;
  395.       Creat   : Boolean;
  396.       Amethod : Character;
  397.       Fopstr  : out Fopen_String)
  398.    is
  399.       Fptr  : Positive;
  400.  
  401.    begin
  402.       case Mode is
  403.          when In_File =>
  404.             if Creat then
  405.                Fopstr (1) := 'w';
  406.                Fopstr (2) := '+';
  407.                Fptr := 3;
  408.             else
  409.                Fopstr (1) := 'r';
  410.                Fptr := 2;
  411.             end if;
  412.  
  413.          when Out_File =>
  414.             if Amethod = 'D' and not Creat then
  415.                Fopstr (1) := 'r';
  416.                Fopstr (2) := '+';
  417.                Fptr := 3;
  418.             else
  419.                Fopstr (1) := 'w';
  420.                Fptr := 2;
  421.             end if;
  422.  
  423.          when Inout_File | Append_File =>
  424.             if Creat then
  425.                Fopstr (1) := 'w';
  426.             else
  427.                Fopstr (1) := 'r';
  428.             end if;
  429.  
  430.             Fopstr (2) := '+';
  431.             Fptr := 3;
  432.  
  433.       end case;
  434.  
  435.       --  If text_translation_required is true then we need to append
  436.       --  either a t or b to the string to get the right mode
  437.  
  438.       if text_translation_required then
  439.          if Text then
  440.             Fopstr (Fptr) := 't';
  441.          else
  442.             Fopstr (Fptr) := 'b';
  443.          end if;
  444.  
  445.          Fptr := Fptr + 1;
  446.       end if;
  447.  
  448.       Fopstr (Fptr) := ASCII.NUL;
  449.    end Fopen_Mode;
  450.  
  451.    ----------
  452.    -- Form --
  453.    ----------
  454.  
  455.    function Form (File : in AFCB_Ptr) return String is
  456.    begin
  457.       if File = null then
  458.          raise Status_Error;
  459.       else
  460.          return File.Form.all (1 .. File.Form'Length - 1);
  461.       end if;
  462.    end Form;
  463.  
  464.    ------------------
  465.    -- Form_Boolean --
  466.    ------------------
  467.  
  468.    function Form_Boolean
  469.      (Form    : String;
  470.       Keyword : String;
  471.       Default : Boolean)
  472.       return    Boolean
  473.    is
  474.       V1, V2 : Natural;
  475.  
  476.    begin
  477.       Form_Parameter (Form, Keyword, V1, V2);
  478.  
  479.       if V1 = 0 then
  480.          return Default;
  481.  
  482.       elsif Form (V1) = 'y' then
  483.          return True;
  484.  
  485.       elsif Form (V1) = 'n' then
  486.          return False;
  487.  
  488.       else
  489.          raise Use_Error;
  490.       end if;
  491.    end Form_Boolean;
  492.  
  493.    ------------------
  494.    -- Form_Integer --
  495.    ------------------
  496.  
  497.    function Form_Integer
  498.      (Form    : String;
  499.       Keyword : String;
  500.       Default : Integer)
  501.       return    Integer
  502.    is
  503.       V1, V2 : Natural;
  504.       V      : Integer;
  505.  
  506.    begin
  507.       Form_Parameter (Form, Keyword, V1, V2);
  508.  
  509.       if V1 = 0 then
  510.          return Default;
  511.  
  512.       else
  513.          V := 0;
  514.  
  515.          for J in V1 .. V2 loop
  516.             if Form (J) not in '0' .. '9' then
  517.                raise Use_Error;
  518.             else
  519.                V := V * 10 + Character'Pos (Form (J)) - Character'Pos ('0');
  520.             end if;
  521.  
  522.             if V > 999_999 then
  523.                raise Use_Error;
  524.             end if;
  525.          end loop;
  526.  
  527.          return V;
  528.       end if;
  529.    end Form_Integer;
  530.  
  531.    --------------------
  532.    -- Form_Parameter --
  533.    --------------------
  534.  
  535.    procedure Form_Parameter
  536.      (Form    : String;
  537.       Keyword : String;
  538.       Start   : out Natural;
  539.       Stop    : out Natural)
  540.   is
  541.  
  542.       Klen : constant Integer := Keyword'Length;
  543.  
  544.    --  Start of processing for Form_Parameter
  545.  
  546.    begin
  547.       for J in Form'First + Klen .. Form'Last - 1 loop
  548.          if Form (J) = '='
  549.            and then Form (J - Klen .. J - 1) = Keyword
  550.          then
  551.             Start := J + 1;
  552.             Stop := Start - 1;
  553.  
  554.             while Form (Stop + 1) /= ASCII.NUL
  555.               and then Form (Stop + 1) /= ','
  556.             loop
  557.                Stop := Stop + 1;
  558.             end loop;
  559.  
  560.             return;
  561.          end if;
  562.       end loop;
  563.  
  564.       Start := 0;
  565.    end Form_Parameter;
  566.  
  567.    -------------
  568.    -- Is_Open --
  569.    -------------
  570.  
  571.    function Is_Open (File : in AFCB_Ptr) return Boolean is
  572.    begin
  573.       return (File /= null);
  574.    end Is_Open;
  575.  
  576.    ----------
  577.    -- Mode --
  578.    ----------
  579.  
  580.    function Mode (File : in AFCB_Ptr) return File_Mode is
  581.    begin
  582.       if File = null then
  583.          raise Status_Error;
  584.       else
  585.          return File.Mode;
  586.       end if;
  587.    end Mode;
  588.  
  589.    ----------
  590.    -- Name --
  591.    ----------
  592.  
  593.    function Name (File : in AFCB_Ptr) return String is
  594.    begin
  595.       if File = null then
  596.          raise Status_Error;
  597.       else
  598.          return File.Name.all (1 .. File.Name'Length - 1);
  599.       end if;
  600.    end Name;
  601.  
  602.    ----------
  603.    -- Open --
  604.    ----------
  605.  
  606.    procedure Open
  607.      (File_Ptr  : in out AFCB_Ptr;
  608.       Dummy_FCB : in out AFCB'Class;
  609.       Mode      : File_Mode;
  610.       Name      : String;
  611.       Form      : String;
  612.       Amethod   : Character;
  613.       Creat     : Boolean;
  614.       Text      : Boolean;
  615.       C_Stream  : FILEs := NULL_Stream)
  616.    is
  617.       Stream : FILEs := C_Stream;
  618.       --  Stream which we open in response to this request
  619.  
  620.       Shared : Shared_Status_Type;
  621.       --  Setting of Shared_Status field for file
  622.  
  623.       Fopstr : aliased Fopen_String;
  624.       --  Mode string used in fopen call
  625.  
  626.       Formstr : aliased String (1 .. Form'Length + 1);
  627.       --  Form string with ASCII.NUL appended, folded to lower case
  628.  
  629.       Tempfile : constant Boolean := (Name'Length = 0);
  630.       --  Indicates temporary file case
  631.  
  632.       Namelen : constant Integer := Integer'Max (L_tmpnam, Name'Length);
  633.       --  Length required for file name, not including final ASCII.NUL
  634.  
  635.       Namestr : aliased String (1 .. Namelen + 1);
  636.       --  Name as given or temporary file name with ASCII.NUL appended
  637.  
  638.       Fullname : aliased String (1 .. max_path_len + 1);
  639.       --  Full name (as required for Name function, and as stored in the
  640.       --  control block in the Name field) with ASCII.NUL appended.
  641.  
  642.       Full_Name_Len : Integer;
  643.       --  Length of name actually stored in Fullname
  644.  
  645.    begin
  646.       if File_Ptr /= null then
  647.          raise Status_Error;
  648.       end if;
  649.  
  650.       --  Acquire form string, setting required NUL terminator
  651.  
  652.       Formstr (1 .. Form'Length) := Form;
  653.       Formstr (Formstr'Last) := ASCII.NUL;
  654.  
  655.       --  Convert form string to lower case
  656.  
  657.       for J in Formstr'Range loop
  658.          if Formstr (J) in 'A' .. 'Z' then
  659.             Formstr (J) := Character'Val (Character'Pos (Formstr (J)) + 32);
  660.          end if;
  661.       end loop;
  662.  
  663.       --  Acquire setting of shared parameter
  664.  
  665.       declare
  666.          V1, V2 : Natural;
  667.  
  668.       begin
  669.          Form_Parameter (Formstr, "shared", V1, V2);
  670.  
  671.          if V1 = 0 then
  672.             Shared := None;
  673.  
  674.          elsif Formstr (V1 .. V2) = "yes" then
  675.             Shared := Yes;
  676.  
  677.          elsif Formstr (V1 .. V2) = "no" then
  678.             Shared := No;
  679.  
  680.          else
  681.             raise Use_Error;
  682.          end if;
  683.       end;
  684.  
  685.       --  Remaining processing is done with tasking locked out. This ensures
  686.       --  that the global data structures (temporary file chain and the open
  687.       --  file chain) retain their integrity.
  688.  
  689.       Locked_Processing : begin
  690.          SSL.Lock_Task.all;
  691.  
  692.          --  If we were given a stream (call from xxx.C_Streams.Open), then set
  693.          --  full name to null and that is all we have to do in this case so
  694.          --  skip to end of processing.
  695.  
  696.          if Stream /= NULL_Stream then
  697.             Fullname (1) := ASCII.Nul;
  698.             Full_Name_Len := 1;
  699.  
  700.          --  Normal case of Open or Create
  701.  
  702.          else
  703.             --  If temporary file case, get temporary file name and add
  704.             --  to the list of temporary files to be deleted on exit.
  705.  
  706.             if Tempfile then
  707.                if not Creat then
  708.                   raise Name_Error;
  709.                end if;
  710.  
  711.                tmpnam (Namestr'Address);
  712.  
  713.                if Namestr (1) = ASCII.NUL then
  714.                   raise Use_Error;
  715.                end if;
  716.  
  717.                Temp_Files :=
  718.                  new Temp_File_Record'(Name => Namestr, Next => Temp_Files);
  719.  
  720.             --  Normal case of non-null name given
  721.  
  722.             else
  723.                Namestr (1 .. Name'Length) := Name;
  724.                Namestr (Name'Length + 1)  := ASCII.NUL;
  725.             end if;
  726.  
  727.             --  Get full name in accordance with the advice of RM A.8.2(22).
  728.  
  729.             full_name (Namestr'Address, Fullname'Address);
  730.  
  731.             if Fullname (1) = ASCII.NUL then
  732.                raise Use_Error;
  733.             end if;
  734.  
  735.             for J in Fullname'Range loop
  736.                if Fullname (J) = ASCII.NUL then
  737.                   Full_Name_Len := J;
  738.                   exit;
  739.                end if;
  740.             end loop;
  741.  
  742.             --  If Shared=None or Shared=Yes, then check for the existence
  743.             --  of another file with exactly the same full name.
  744.  
  745.             if Shared /= No then
  746.                declare
  747.                   P : AFCB_Ptr;
  748.  
  749.                begin
  750.                   P := Open_Files;
  751.                   while P /= null loop
  752.                      if Fullname (1 .. Full_Name_Len) = P.Name.all then
  753.  
  754.                         --  If we get a match, and either file has Shared=None,
  755.                         --  then raise Use_Error, since we don't allow two
  756.                         --  files of the same name to be opened unless they
  757.                         --  specify the required sharing mode.
  758.  
  759.                         if Shared = None
  760.                           or else P.Shared_Status = None
  761.                         then
  762.                            raise Use_Error;
  763.  
  764.                         --  If both files have Shared=Yes, then we acquire the
  765.                         --  stream from the located file to use as our stream.
  766.  
  767.                         elsif Shared = Yes
  768.                           and then P.Shared_Status = Yes
  769.                         then
  770.                            Stream := P.Stream;
  771.                            exit;
  772.  
  773.                         --  Otherwise one of the files has Shared=Yes and one
  774.                         --  has Shared=No. If the current file has Shared=No
  775.                         --  then all is well but we don't want to share any
  776.                         --  other file's stream. If the current file has
  777.                         --  Shared=Yes, we would like to share a stream, but
  778.                         --  not from a file that has Shared=No, so in either
  779.                         --  case we just keep going on the search.
  780.  
  781.                         else
  782.                            null;
  783.                         end if;
  784.                      end if;
  785.  
  786.                      P := P.Next;
  787.                   end loop;
  788.                end;
  789.             end if;
  790.  
  791.             --  Open specified file if we did not find an existing stream
  792.  
  793.             if Stream = NULL_Stream then
  794.                Fopen_Mode (Mode, Text, Creat, Amethod, Fopstr);
  795.  
  796.                --  A special case, if we are opening (OPEN case) a file and
  797.                --  the mode returned by Fopen_Mode is not "r" or "r+", then
  798.                --  we first make sure that the file exists as required by
  799.                --  Ada semantics.
  800.  
  801.                if Creat = False and then Fopstr (1) /= 'r' then
  802.                   if file_exists (Namestr'Address) = 0 then
  803.                      raise Name_Error;
  804.                   end if;
  805.                end if;
  806.  
  807.                Stream := fopen (Namestr'Address, Fopstr'Address);
  808.  
  809.                if Stream = NULL_Stream then
  810.                   if file_exists (Namestr'Address) = 0 then
  811.                      raise Name_Error;
  812.                   else
  813.                      raise Use_Error;
  814.                   end if;
  815.                end if;
  816.             end if;
  817.          end if;
  818.  
  819.          --  Stream has been successfully located or opened, so now we are
  820.          --  committed to completing the opening of the file. Allocate block
  821.          --  on heap and fill in its fields.
  822.  
  823.          File_Ptr := AFCB_Allocate (Dummy_FCB);
  824.  
  825.          File_Ptr.Is_Regular_File   := (is_regular_file
  826.                                          (fileno (Stream)) /= 0);
  827.          File_Ptr.Is_System_File    := False;
  828.          File_Ptr.Is_Text_File      := Text;
  829.          File_Ptr.Shared_Status     := Shared;
  830.          File_Ptr.Access_Method     := Amethod;
  831.          File_Ptr.Stream            := Stream;
  832.          File_Ptr.Form              := new String'(Formstr);
  833.          File_Ptr.Name              := new String'(Fullname
  834.                                                     (1 .. Full_Name_Len));
  835.          File_Ptr.Mode              := Mode;
  836.          File_Ptr.Is_Temporary_File := False;
  837.  
  838.          Chain_File (File_Ptr);
  839.          SSL.Unlock_Task.all;
  840.  
  841.       exception
  842.          when others =>
  843.             SSL.Unlock_Task.all;
  844.             raise;
  845.       end Locked_Processing;
  846.  
  847.       Append_Set (File_Ptr);
  848.    end Open;
  849.  
  850.    --------------
  851.    -- Read_Buf --
  852.    --------------
  853.  
  854.    procedure Read_Buf (File : AFCB_Ptr; Buf : Address; Siz : size_t) is
  855.       Nread : size_t;
  856.  
  857.    begin
  858.       Nread := fread (Buf, 1, Siz, File.Stream);
  859.  
  860.       if Nread = Siz then
  861.          return;
  862.  
  863.       elsif ferror (File.Stream) /= 0 then
  864.          raise Device_Error;
  865.  
  866.       elsif Nread = 0 then
  867.          raise End_Error;
  868.  
  869.       else -- 0 < Nread < Siz
  870.          raise Data_Error;
  871.       end if;
  872.  
  873.    end Read_Buf;
  874.  
  875.    procedure Read_Buf
  876.      (File  : AFCB_Ptr;
  877.       Buf   : Address;
  878.       Siz   : in Interfaces.C_Streams.size_t;
  879.       Count : out Interfaces.C_Streams.size_t)
  880.    is
  881.    begin
  882.       Count := fread (Buf, 1, Siz, File.Stream);
  883.  
  884.       if Count = 0 and then ferror (File.Stream) /= 0 then
  885.          raise Device_Error;
  886.       end if;
  887.    end Read_Buf;
  888.  
  889.    -----------
  890.    -- Reset --
  891.    -----------
  892.  
  893.    --  The reset which does not change the mode simply does a rewind.
  894.  
  895.    procedure Reset (File : in out AFCB_Ptr) is
  896.    begin
  897.       Check_File_Open (File);
  898.       Reset (File, File.Mode);
  899.    end Reset;
  900.  
  901.    --  The reset with a change in mode is done using freopen, and is
  902.    --  not permitted except for regular files (since otherwise there
  903.    --  is no name for the freopen, and in any case it seems meaningless)
  904.  
  905.    procedure Reset (File : in out AFCB_Ptr; Mode : in File_Mode) is
  906.       Fopstr : aliased Fopen_String;
  907.  
  908.    begin
  909.       Check_File_Open (File);
  910.  
  911.       --  Change of mode not allowed for shared file or file with no name
  912.       --  or file that is not a regular file, or for a system file.
  913.  
  914.       if File.Shared_Status = Yes
  915.         or else File.Name'Length <= 1
  916.         or else File.Is_System_File
  917.         or else (not File.Is_Regular_File)
  918.       then
  919.          raise Use_Error;
  920.  
  921.       --  For In_File or Inout_File for a regular file, we can just do a
  922.       --  rewind if the mode is unchanged, which is more efficient than
  923.       --  doing a full reopen.
  924.  
  925.       elsif Mode = File.Mode
  926.         and then Mode <= Inout_File
  927.       then
  928.          rewind (File.Stream);
  929.  
  930.       --  Here the change of mode is permitted, we do it by reopening the
  931.       --  file in the new mode and replacing the stream with a new stream.
  932.  
  933.       else
  934.          Fopen_Mode
  935.            (Mode, File.Is_Text_File, False, File.Access_Method, Fopstr);
  936.  
  937.          File.Stream :=
  938.            freopen (File.Name.all'Address, Fopstr'Address, File.Stream);
  939.  
  940.          if File.Stream = NULL_Stream then
  941.             Close (File);
  942.             raise Use_Error;
  943.  
  944.          else
  945.             File.Mode := Mode;
  946.             Append_Set (File);
  947.          end if;
  948.       end if;
  949.    end Reset;
  950.  
  951.    ---------------
  952.    -- Write_Buf --
  953.    ---------------
  954.  
  955.    procedure Write_Buf (File : AFCB_Ptr; Buf : Address; Siz : size_t) is
  956.    begin
  957.       --  Note: for most purposes, the Siz and 1 parameters in the fwrite
  958.       --  call could be reversed, but on VMS, this is a better choice, since
  959.       --  for some file formats, reversing the parameters results in records
  960.       --  of one byte each.
  961.  
  962.       SSL.Abort_Defer.all;
  963.  
  964.       if fwrite (Buf, Siz, 1, File.Stream) /= 1 then
  965.          if Siz /= 0 then
  966.             SSL.Abort_Undefer.all;
  967.             raise Device_Error;
  968.          end if;
  969.       end if;
  970.  
  971.       SSL.Abort_Undefer.all;
  972.    end Write_Buf;
  973.  
  974.    procedure Make_Unbuffered (File : AFCB_Ptr) is
  975.       status : Integer;
  976.  
  977.    begin
  978.       status := setvbuf (File.Stream, Null_Address, IONBF, 0);
  979.    end Make_Unbuffered;
  980.  
  981.    procedure Make_Line_Buffered
  982.      (File     : AFCB_Ptr;
  983.       Line_Siz : Interfaces.C_Streams.size_t) is
  984.       status   : Integer;
  985.  
  986.    begin
  987.       status := setvbuf (File.Stream, Null_Address, IOLBF, Line_Siz);
  988.    end Make_Line_Buffered;
  989.  
  990.    procedure Make_Buffered
  991.      (File     : AFCB_Ptr;
  992.       Buf_Siz  : Interfaces.C_Streams.size_t) is
  993.       status   : Integer;
  994.  
  995.    begin
  996.       status := setvbuf (File.Stream, Null_Address, IOFBF, Buf_Siz);
  997.    end Make_Buffered;
  998.  
  999. end System.File_IO;
  1000.