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 / a-textio.adb < prev    next >
Text File  |  2000-07-19  |  46KB  |  1,749 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                          A D A . T E X T _ I O                           --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.74 $
  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.Streams;          use Ada.Streams;
  37. with Interfaces.C_Streams; use Interfaces.C_Streams;
  38. with System;
  39. with System.File_IO;
  40. with Unchecked_Conversion;
  41. with Unchecked_Deallocation;
  42.  
  43. pragma Elaborate_All (System.File_IO);
  44. --  Needed because of calls to Chain_File in package body elaboration
  45.  
  46. package body Ada.Text_IO is
  47.  
  48.    package FIO renames System.File_IO;
  49.  
  50.    subtype AP is FCB.AFCB_Ptr;
  51.  
  52.    function To_FCB is new Unchecked_Conversion (File_Mode, FCB.File_Mode);
  53.    function To_TIO is new Unchecked_Conversion (FCB.File_Mode, File_Mode);
  54.    use type FCB.File_Mode;
  55.  
  56.    -------------------
  57.    -- AFCB_Allocate --
  58.    -------------------
  59.  
  60.    function AFCB_Allocate (Control_Block : Text_AFCB) return FCB.AFCB_Ptr is
  61.    begin
  62.       return new Text_AFCB;
  63.    end AFCB_Allocate;
  64.  
  65.    ----------------
  66.    -- AFCB_Close --
  67.    ----------------
  68.  
  69.    procedure AFCB_Close (File : access Text_AFCB) is
  70.    begin
  71.       --  If the file being closed is one of the current files, then close
  72.       --  the corresponding current file. It is not clear that this action
  73.       --  is required (RM A.10.3(23)) but it seems reasonable, and besides
  74.       --  ACVC test CE3208A expects this behavior.
  75.  
  76.       if File_Type (File) = Current_In then
  77.          Current_In := null;
  78.       elsif File_Type (File) = Current_Out then
  79.          Current_Out := null;
  80.       elsif File_Type (File) = Current_Err then
  81.          Current_Err := null;
  82.       end if;
  83.  
  84.       Terminate_Line (File_Type (File));
  85.    end AFCB_Close;
  86.  
  87.    ---------------
  88.    -- AFCB_Free --
  89.    ---------------
  90.  
  91.    procedure AFCB_Free (File : access Text_AFCB) is
  92.       type FCB_Ptr is access all Text_AFCB;
  93.       FT : FCB_Ptr := FCB_Ptr (File);
  94.  
  95.       procedure Free is new Unchecked_Deallocation (Text_AFCB, FCB_Ptr);
  96.  
  97.    begin
  98.       Free (FT);
  99.    end AFCB_Free;
  100.  
  101.    -----------
  102.    -- Close --
  103.    -----------
  104.  
  105.    procedure Close (File : in out File_Type) is
  106.    begin
  107.       FIO.Close (AP (File));
  108.    end Close;
  109.  
  110.    ---------
  111.    -- Col --
  112.    ---------
  113.  
  114.    --  Note: we assume that it is impossible in practice for the column
  115.    --  to exceed the value of Count'Last, i.e. no check is required for
  116.    --  overflow raising layout error.
  117.  
  118.    function Col (File : in File_Type) return Positive_Count is
  119.    begin
  120.       FIO.Check_File_Open (AP (File));
  121.       return File.Col;
  122.    end Col;
  123.  
  124.    function Col return Positive_Count is
  125.    begin
  126.       return Col (Current_Out);
  127.    end Col;
  128.  
  129.    ------------
  130.    -- Create --
  131.    ------------
  132.  
  133.    procedure Create
  134.      (File : in out File_Type;
  135.       Mode : in File_Mode := Out_File;
  136.       Name : in String := "";
  137.       Form : in String := "")
  138.    is
  139.       File_Control_Block : Text_AFCB;
  140.  
  141.    begin
  142.       FIO.Open (File_Ptr  => AP (File),
  143.                 Dummy_FCB => File_Control_Block,
  144.                 Mode      => To_FCB (Mode),
  145.                 Name      => Name,
  146.                 Form      => Form,
  147.                 Amethod   => 'T',
  148.                 Creat     => True,
  149.                 Text      => True);
  150.  
  151.       File.Self := File;
  152.    end Create;
  153.  
  154.    -------------------
  155.    -- Current_Error --
  156.    -------------------
  157.  
  158.    function Current_Error return File_Type is
  159.    begin
  160.       return Current_Err;
  161.    end Current_Error;
  162.  
  163.    function Current_Error return File_Access is
  164.    begin
  165.       return Current_Err.Self'Access;
  166.    end Current_Error;
  167.  
  168.    -------------------
  169.    -- Current_Input --
  170.    -------------------
  171.  
  172.    function Current_Input return File_Type is
  173.    begin
  174.       return Current_In;
  175.    end Current_Input;
  176.  
  177.    function Current_Input return File_Access is
  178.    begin
  179.       return Current_In.Self'Access;
  180.    end Current_Input;
  181.  
  182.    --------------------
  183.    -- Current_Output --
  184.    --------------------
  185.  
  186.    function Current_Output return File_Type is
  187.    begin
  188.       return Current_Out;
  189.    end Current_Output;
  190.  
  191.    function Current_Output return File_Access is
  192.    begin
  193.       return Current_Out.Self'Access;
  194.    end Current_Output;
  195.  
  196.    ------------
  197.    -- Delete --
  198.    ------------
  199.  
  200.    procedure Delete (File : in out File_Type) is
  201.    begin
  202.       FIO.Delete (AP (File));
  203.    end Delete;
  204.  
  205.    -----------------
  206.    -- End_Of_File --
  207.    -----------------
  208.  
  209.    function End_Of_File (File : in File_Type) return Boolean is
  210.       ch  : int;
  211.  
  212.    begin
  213.       FIO.Check_Read_Status (AP (File));
  214.  
  215.       if File.Before_LM then
  216.  
  217.          if File.Before_LM_PM then
  218.             return Nextc (File) = EOF;
  219.          end if;
  220.  
  221.       else
  222.          ch := Getc (File);
  223.  
  224.          if ch = EOF then
  225.             return True;
  226.  
  227.          elsif ch /= LM then
  228.             Ungetc (ch, File);
  229.             return False;
  230.  
  231.          else -- ch = LM
  232.             File.Before_LM := True;
  233.          end if;
  234.       end if;
  235.  
  236.       --  Here we are just past the line mark with Before_LM set so that we
  237.       --  do not have to try to back up past the LM, thus avoiding the need
  238.       --  to back up more than one character.
  239.  
  240.       ch := Getc (File);
  241.  
  242.       if ch = EOF then
  243.          return True;
  244.  
  245.       elsif ch = PM and then File.Is_Regular_File then
  246.          File.Before_LM_PM := True;
  247.          return Nextc (File) = EOF;
  248.  
  249.       --  Here if neither EOF nor PM followed end of line
  250.  
  251.       else
  252.          Ungetc (ch, File);
  253.          return False;
  254.       end if;
  255.  
  256.    end End_Of_File;
  257.  
  258.    function End_Of_File return Boolean is
  259.    begin
  260.       return End_Of_File (Current_In);
  261.    end End_Of_File;
  262.  
  263.    -----------------
  264.    -- End_Of_Line --
  265.    -----------------
  266.  
  267.    function End_Of_Line (File : in File_Type) return Boolean is
  268.       ch : int;
  269.  
  270.    begin
  271.       FIO.Check_Read_Status (AP (File));
  272.  
  273.       if File.Before_LM then
  274.          return True;
  275.  
  276.       else
  277.          ch := Getc (File);
  278.  
  279.          if ch = EOF then
  280.             return True;
  281.  
  282.          else
  283.             Ungetc (ch, File);
  284.             return (ch = LM);
  285.          end if;
  286.       end if;
  287.    end End_Of_Line;
  288.  
  289.    function End_Of_Line return Boolean is
  290.    begin
  291.       return End_Of_Line (Current_In);
  292.    end End_Of_Line;
  293.  
  294.    -----------------
  295.    -- End_Of_Page --
  296.    -----------------
  297.  
  298.    function End_Of_Page (File : in File_Type) return Boolean is
  299.       ch  : int;
  300.  
  301.    begin
  302.       FIO.Check_Read_Status (AP (File));
  303.  
  304.       if not File.Is_Regular_File then
  305.          return False;
  306.  
  307.       elsif File.Before_LM then
  308.          if File.Before_LM_PM then
  309.             return True;
  310.          end if;
  311.  
  312.       else
  313.          ch := Getc (File);
  314.  
  315.          if ch = EOF then
  316.             return True;
  317.  
  318.          elsif ch /= LM then
  319.             Ungetc (ch, File);
  320.             return False;
  321.  
  322.          else -- ch = LM
  323.             File.Before_LM := True;
  324.          end if;
  325.       end if;
  326.  
  327.       --  Here we are just past the line mark with Before_LM set so that we
  328.       --  do not have to try to back up past the LM, thus avoiding the need
  329.       --  to back up more than one character.
  330.  
  331.       ch := Nextc (File);
  332.  
  333.       return ch = PM or else ch = EOF;
  334.    end End_Of_Page;
  335.  
  336.    function End_Of_Page return Boolean is
  337.    begin
  338.       return End_Of_Page (Current_In);
  339.    end End_Of_Page;
  340.  
  341.    -----------
  342.    -- Flush --
  343.    -----------
  344.  
  345.    procedure Flush (File : in File_Type) is
  346.    begin
  347.       FIO.Flush (AP (File));
  348.    end Flush;
  349.  
  350.    procedure Flush is
  351.    begin
  352.       Flush (Current_Out);
  353.    end Flush;
  354.  
  355.    ----------
  356.    -- Form --
  357.    ----------
  358.  
  359.    function Form (File : in File_Type) return String is
  360.    begin
  361.       return FIO.Form (AP (File));
  362.    end Form;
  363.  
  364.    ---------
  365.    -- Get --
  366.    ---------
  367.  
  368.    procedure Get
  369.      (File : in File_Type;
  370.       Item : out Character)
  371.    is
  372.       ch : int;
  373.  
  374.    begin
  375.       FIO.Check_Read_Status (AP (File));
  376.  
  377.       if File.Before_LM then
  378.          File.Before_LM := False;
  379.          File.Col := 1;
  380.  
  381.          if File.Before_LM_PM then
  382.             File.Line := 1;
  383.             File.Page := File.Page + 1;
  384.             File.Before_LM_PM := False;
  385.          else
  386.             File.Line := File.Line + 1;
  387.          end if;
  388.       end if;
  389.  
  390.       loop
  391.          ch := Getc (File);
  392.  
  393.          if ch = EOF then
  394.             raise End_Error;
  395.  
  396.          elsif ch = LM then
  397.             File.Line := File.Line + 1;
  398.             File.Col := 1;
  399.  
  400.          elsif ch = PM and then File.Is_Regular_File then
  401.             File.Page := File.Page + 1;
  402.             File.Line := 1;
  403.  
  404.          else
  405.             Item := Character'Val (ch);
  406.             File.Col := File.Col + 1;
  407.             return;
  408.          end if;
  409.       end loop;
  410.    end Get;
  411.  
  412.    procedure Get (Item : out Character) is
  413.    begin
  414.       Get (Current_In, Item);
  415.    end Get;
  416.  
  417.    procedure Get
  418.      (File : in File_Type;
  419.       Item : out String)
  420.    is
  421.       ch : int;
  422.       J  : Natural;
  423.  
  424.    begin
  425.       FIO.Check_Read_Status (AP (File));
  426.  
  427.       if File.Before_LM then
  428.          File.Before_LM := False;
  429.          File.Before_LM_PM := False;
  430.          File.Col := 1;
  431.  
  432.          if File.Before_LM_PM then
  433.             File.Line := 1;
  434.             File.Page := File.Page + 1;
  435.             File.Before_LM_PM := False;
  436.  
  437.          else
  438.             File.Line := File.Line + 1;
  439.          end if;
  440.       end if;
  441.  
  442.       J := Item'First;
  443.       while J <= Item'Last loop
  444.          ch := Getc (File);
  445.  
  446.          if ch = EOF then
  447.             raise End_Error;
  448.  
  449.          elsif ch = LM then
  450.             File.Line := File.Line + 1;
  451.             File.Col := 1;
  452.  
  453.          elsif ch = PM and then File.Is_Regular_File then
  454.             File.Page := File.Page + 1;
  455.             File.Line := 1;
  456.  
  457.          else
  458.             Item (J) := Character'Val (ch);
  459.             J := J + 1;
  460.             File.Col := File.Col + 1;
  461.          end if;
  462.       end loop;
  463.    end Get;
  464.  
  465.    procedure Get (Item : out String) is
  466.    begin
  467.       Get (Current_In, Item);
  468.    end Get;
  469.  
  470.    ----------
  471.    -- Getc --
  472.    ----------
  473.    function Getc (File : File_Type) return int is
  474.       ch : int;
  475.  
  476.    begin
  477.       ch := fgetc (File.Stream);
  478.  
  479.       if ch = EOF and then ferror (File.Stream) /= 0 then
  480.          raise Device_Error;
  481.       else
  482.          return ch;
  483.       end if;
  484.    end Getc;
  485.  
  486.    -------------------
  487.    -- Get_Immediate --
  488.    -------------------
  489.  
  490.    --  More work required here ???
  491.  
  492.    procedure Get_Immediate
  493.      (File : in File_Type;
  494.       Item : out Character)
  495.    is
  496.       ch          : int;
  497.       end_of_file : int;
  498.  
  499.       procedure getc_immediate
  500.         (stream : FILEs; ch : out int; end_of_file : out int);
  501.       pragma Import (C, getc_immediate, "getc_immediate");
  502.  
  503.    begin
  504.       FIO.Check_Read_Status (AP (File));
  505.  
  506.       if File.Before_LM then
  507.          File.Before_LM := False;
  508.          File.Before_LM_PM := False;
  509.          ch := LM;
  510.  
  511.       else
  512.          getc_immediate (File.Stream, ch, end_of_file);
  513.  
  514.          if ferror (File.Stream) /= 0 then
  515.             raise Device_Error;
  516.          elsif end_of_file /= 0 then
  517.             raise End_Error;
  518.          end if;
  519.       end if;
  520.  
  521.       Item := Character'Val (ch);
  522.  
  523.    end Get_Immediate;
  524.  
  525.    procedure Get_Immediate
  526.      (Item : out Character)
  527.    is
  528.    begin
  529.       Get_Immediate (Current_In, Item);
  530.    end Get_Immediate;
  531.  
  532.    procedure Get_Immediate
  533.      (File      : in File_Type;
  534.       Item      : out Character;
  535.       Available : out Boolean)
  536.    is
  537.       ch          : int;
  538.       end_of_file : int;
  539.       avail       : int;
  540.  
  541.       procedure getc_immediate_nowait
  542.         (stream      : FILEs;
  543.          ch          : out int;
  544.          end_of_file : out int;
  545.          avail       : out int);
  546.       pragma Import (C, getc_immediate_nowait, "getc_immediate_nowait");
  547.  
  548.    begin
  549.       FIO.Check_Read_Status (AP (File));
  550.  
  551.       if File.Before_LM then
  552.          File.Before_LM := False;
  553.          File.Before_LM_PM := False;
  554.          ch := LM;
  555.  
  556.       else
  557.          getc_immediate_nowait (File.Stream, ch, end_of_file, avail);
  558.  
  559.          if ferror (File.Stream) /= 0 then
  560.             raise Device_Error;
  561.  
  562.          elsif end_of_file /= 0 then
  563.             raise End_Error;
  564.  
  565.          elsif avail = 0 then
  566.             Available := False;
  567.  
  568.          else
  569.             Available := True;
  570.             Item := Character'Val (ch);
  571.          end if;
  572.       end if;
  573.  
  574.    end Get_Immediate;
  575.  
  576.    procedure Get_Immediate
  577.      (Item      : out Character;
  578.       Available : out Boolean)
  579.    is
  580.    begin
  581.       Get_Immediate (Current_In, Item, Available);
  582.    end Get_Immediate;
  583.  
  584.    --------------
  585.    -- Get_Line --
  586.    --------------
  587.  
  588.    procedure Get_Line
  589.      (File : in File_Type;
  590.       Item : out String;
  591.       Last : out Natural)
  592.    is
  593.       ch : int;
  594.  
  595.    begin
  596.       FIO.Check_Read_Status (AP (File));
  597.       Last := Item'First - 1;
  598.  
  599.       --  Immediate exit for null string, this is a case in which we do not
  600.       --  need to test for end of file and we do not skip a line mark under
  601.       --  any circumstances.
  602.  
  603.       if Last >= Item'Last then
  604.          return;
  605.       end if;
  606.  
  607.       --  Here we have at least one character, if we are immediately before
  608.       --  a line mark, then we will just skip past it storing no characters.
  609.  
  610.       if File.Before_LM then
  611.          File.Before_LM := False;
  612.          File.Before_LM_PM := False;
  613.  
  614.       --  Otherwise we need to read some characters
  615.  
  616.       else
  617.          ch := Getc (File);
  618.  
  619.          --  If we are at the end of file now, it means we are trying to
  620.          --  skip a file terminator and we raise End_Error (RM A.10.7(20))
  621.  
  622.          if ch = EOF then
  623.             raise End_Error;
  624.          end if;
  625.  
  626.          --  Loop through characters. Don't bother if we hit a page mark,
  627.          --  since in normal files, page marks can only follow line marks
  628.          --  in any case and we only promise to treat the page nonsense
  629.          --  correctly in the absense of such rogue page marks.
  630.  
  631.          loop
  632.             --  Exit the loop if read is terminated by encountering line mark
  633.  
  634.             exit when ch = LM;
  635.  
  636.             --  Otherwise store the character, note that we know that ch is
  637.             --  something other than LM or EOF. It could possibly be a page
  638.             --  mark if there is a stray page mark in the middle of a line,
  639.             --  but this is not an official page mark in any case, since
  640.             --  official page marks can only follow a line mark. The whole
  641.             --  page business is pretty much nonsense anyway, so we do not
  642.             --  want to waste time trying to make sense out of non-standard
  643.             --  page marks in the file! This means that the behavior of
  644.             --  Get_Line is different from repeated Get of a character, but
  645.             --  that's too bad. We only promise that page numbers etc make
  646.             --  sense if the file is formatted in a standard manner.
  647.  
  648.             --  Note: we do not adjust the column number because it is quicker
  649.             --  to adjust it once at the end of the operation than incrementing
  650.             --  it each time around the loop.
  651.  
  652.             Last := Last + 1;
  653.             Item (Last) := Character'Val (ch);
  654.  
  655.             --  All done if the string is full, this is the case in which
  656.             --  we do not skip the following line mark. We need to adjust
  657.             --  the column number in this case.
  658.  
  659.             if Last = Item'Last then
  660.                File.Col := File.Col + Count (Item'Length);
  661.                return;
  662.             end if;
  663.  
  664.             --  Otherwise read next character. We also exit from the loop if
  665.             --  we read an end of file. This is the case where the last line
  666.             --  is not terminated with a line mark, and we consider that there
  667.             --  is an implied line mark in this case (this is a non-standard
  668.             --  file, but it is nice to treat it reasonably).
  669.  
  670.             ch := Getc (File);
  671.             exit when ch = EOF;
  672.          end loop;
  673.       end if;
  674.  
  675.       --  We have skipped past, but not stored, a line mark. Skip following
  676.       --  page mark if one follows, but do not do this for a non-regular
  677.       --  file (since otherwise we get annoying wait for an extra character)
  678.  
  679.       File.Line := File.Line + 1;
  680.       File.Col := 1;
  681.  
  682.       if File.Before_LM_PM then
  683.          File.Line := 1;
  684.          File.Before_LM_PM := False;
  685.          File.Page := File.Page + 1;
  686.  
  687.       elsif File.Is_Regular_File then
  688.          ch := Getc (File);
  689.  
  690.          if ch = PM and then File.Is_Regular_File then
  691.             File.Line := 1;
  692.             File.Page := File.Page + 1;
  693.          else
  694.             Ungetc (ch, File);
  695.          end if;
  696.       end if;
  697.    end Get_Line;
  698.  
  699.    procedure Get_Line
  700.      (Item : out String;
  701.       Last : out Natural)
  702.    is
  703.    begin
  704.       Get_Line (Current_In, Item, Last);
  705.    end Get_Line;
  706.  
  707.    -------------
  708.    -- Is_Open --
  709.    -------------
  710.  
  711.    function Is_Open (File : in File_Type) return Boolean is
  712.    begin
  713.       return FIO.Is_Open (AP (File));
  714.    end Is_Open;
  715.  
  716.    ----------
  717.    -- Line --
  718.    ----------
  719.  
  720.    --  Note: we assume that it is impossible in practice for the line
  721.    --  to exceed the value of Count'Last, i.e. no check is required for
  722.    --  overflow raising layout error.
  723.  
  724.    function Line (File : in File_Type) return Positive_Count is
  725.    begin
  726.       FIO.Check_File_Open (AP (File));
  727.       return File.Line;
  728.    end Line;
  729.  
  730.    function Line return Positive_Count is
  731.    begin
  732.       return Line (Current_Out);
  733.    end Line;
  734.  
  735.    -----------------
  736.    -- Line_Length --
  737.    -----------------
  738.  
  739.    function Line_Length (File : in File_Type) return Count is
  740.    begin
  741.       FIO.Check_Write_Status (AP (File));
  742.       return File.Line_Length;
  743.    end Line_Length;
  744.  
  745.    function Line_Length return Count is
  746.    begin
  747.       return Line_Length (Current_Out);
  748.    end Line_Length;
  749.  
  750.    ----------------
  751.    -- Look_Ahead --
  752.    ----------------
  753.  
  754.    procedure Look_Ahead
  755.      (File        : in File_Type;
  756.       Item        : out Character;
  757.       End_Of_Line : out Boolean)
  758.    is
  759.       ch : int;
  760.  
  761.    begin
  762.       FIO.Check_Read_Status (AP (File));
  763.  
  764.       if File.Before_LM then
  765.          End_Of_Line := True;
  766.          Item := ASCII.NUL;
  767.  
  768.       else
  769.          ch := Nextc (File);
  770.  
  771.          if ch = LM
  772.            or else ch = EOF
  773.            or else (ch = PM and then File.Is_Regular_File)
  774.          then
  775.             End_Of_Line := True;
  776.             Item := ASCII.NUL;
  777.          else
  778.             End_Of_Line := False;
  779.             Item := Character'Val (ch);
  780.          end if;
  781.       end if;
  782.    end Look_Ahead;
  783.  
  784.    procedure Look_Ahead
  785.      (Item        : out Character;
  786.       End_Of_Line : out Boolean)
  787.    is
  788.    begin
  789.       Look_Ahead (Current_In, Item, End_Of_Line);
  790.    end Look_Ahead;
  791.  
  792.    ----------
  793.    -- Mode --
  794.    ----------
  795.  
  796.    function Mode (File : in File_Type) return File_Mode is
  797.    begin
  798.       return To_TIO (FIO.Mode (AP (File)));
  799.    end Mode;
  800.  
  801.    ----------
  802.    -- Name --
  803.    ----------
  804.  
  805.    function Name (File : in File_Type) return String is
  806.    begin
  807.       return FIO.Name (AP (File));
  808.    end Name;
  809.  
  810.    --------------
  811.    -- New_Line --
  812.    --------------
  813.  
  814.    procedure New_Line
  815.      (File    : in File_Type;
  816.       Spacing : in Positive_Count := 1)
  817.    is
  818.    begin
  819.       --  Raise Constraint_Error if out of range value. The reason for this
  820.       --  explicit test is that we don't want junk values around, even if
  821.       --  checks are off in the caller.
  822.  
  823.       if Spacing not in Positive_Count then
  824.          raise Constraint_Error;
  825.       end if;
  826.  
  827.       FIO.Check_Write_Status (AP (File));
  828.  
  829.       for K in 1 .. Spacing loop
  830.          Putc (LM, File);
  831.          File.Line := File.Line + 1;
  832.  
  833.          if File.Page_Length /= 0
  834.            and then File.Line > File.Page_Length
  835.          then
  836.             Putc (PM, File);
  837.             File.Line := 1;
  838.             File.Page := File.Page + 1;
  839.          end if;
  840.       end loop;
  841.  
  842.       File.Col := 1;
  843.    end New_Line;
  844.  
  845.    procedure New_Line (Spacing : in Positive_Count := 1) is
  846.    begin
  847.       New_Line (Current_Out, Spacing);
  848.    end New_Line;
  849.  
  850.    --------------
  851.    -- New_Page --
  852.    --------------
  853.  
  854.    procedure New_Page (File : in File_Type) is
  855.    begin
  856.       FIO.Check_Write_Status (AP (File));
  857.  
  858.       if File.Col /= 1 or else File.Line = 1 then
  859.          Putc (LM, File);
  860.       end if;
  861.  
  862.       Putc (PM, File);
  863.       File.Page := File.Page + 1;
  864.       File.Line := 1;
  865.       File.Col := 1;
  866.    end New_Page;
  867.  
  868.    procedure New_Page is
  869.    begin
  870.       New_Page (Current_Out);
  871.    end New_Page;
  872.  
  873.    -----------
  874.    -- Nextc --
  875.    -----------
  876.  
  877.    function Nextc (File : File_Type) return int is
  878.       ch : int;
  879.  
  880.    begin
  881.       ch := fgetc (File.Stream);
  882.  
  883.       if ch = EOF then
  884.          if ferror (File.Stream) /= 0 then
  885.             raise Device_Error;
  886.          end if;
  887.  
  888.       else
  889.          if ungetc (ch, File.Stream) = EOF then
  890.             raise Device_Error;
  891.          end if;
  892.       end if;
  893.  
  894.       return ch;
  895.    end Nextc;
  896.  
  897.    ----------
  898.    -- Open --
  899.    ----------
  900.  
  901.    procedure Open
  902.      (File : in out File_Type;
  903.       Mode : in File_Mode;
  904.       Name : in String;
  905.       Form : in String := "")
  906.    is
  907.       File_Control_Block : Text_AFCB;
  908.  
  909.    begin
  910.       FIO.Open (File_Ptr  => AP (File),
  911.                 Dummy_FCB => File_Control_Block,
  912.                 Mode      => To_FCB (Mode),
  913.                 Name      => Name,
  914.                 Form      => Form,
  915.                 Amethod   => 'T',
  916.                 Creat     => False,
  917.                 Text      => True);
  918.  
  919.       File.Self := File;
  920.    end Open;
  921.  
  922.    ----------
  923.    -- Page --
  924.    ----------
  925.  
  926.    --  Note: we assume that it is impossible in practice for the page
  927.    --  to exceed the value of Count'Last, i.e. no check is required for
  928.    --  overflow raising layout error.
  929.  
  930.    function Page (File : in File_Type) return Positive_Count is
  931.    begin
  932.       FIO.Check_File_Open (AP (File));
  933.       return File.Page;
  934.    end Page;
  935.  
  936.    function Page return Positive_Count is
  937.    begin
  938.       return Page (Current_Out);
  939.    end Page;
  940.  
  941.    -----------------
  942.    -- Page_Length --
  943.    -----------------
  944.  
  945.    function Page_Length (File : in File_Type) return Count is
  946.    begin
  947.       FIO.Check_Write_Status (AP (File));
  948.       return File.Page_Length;
  949.    end Page_Length;
  950.  
  951.    function Page_Length return Count is
  952.    begin
  953.       return Page_Length (Current_Out);
  954.    end Page_Length;
  955.  
  956.    ---------
  957.    -- Put --
  958.    ---------
  959.  
  960.    procedure Put
  961.      (File : in File_Type;
  962.       Item : in Character)
  963.    is
  964.    begin
  965.       FIO.Check_Write_Status (AP (File));
  966.  
  967.       if File.Line_Length /= 0 and then File.Col > File.Line_Length then
  968.          New_Line (File);
  969.       end if;
  970.  
  971.       if fputc (Character'Pos (Item), File.Stream) = EOF then
  972.          raise Device_Error;
  973.       end if;
  974.  
  975.       File.Col := File.Col + 1;
  976.    end Put;
  977.  
  978.    procedure Put (Item : in Character) is
  979.    begin
  980.       FIO.Check_Write_Status (AP (Current_Out));
  981.  
  982.       if Current_Out.Line_Length /= 0
  983.         and then Current_Out.Col > Current_Out.Line_Length
  984.       then
  985.          New_Line (Current_Out);
  986.       end if;
  987.  
  988.       if fputc (Character'Pos (Item), Current_Out.Stream) = EOF then
  989.          raise Device_Error;
  990.       end if;
  991.  
  992.       Current_Out.Col := Current_Out.Col + 1;
  993.    end Put;
  994.  
  995.    ---------
  996.    -- Put --
  997.    ---------
  998.  
  999.    procedure Put
  1000.      (File : in File_Type;
  1001.       Item : in String)
  1002.    is
  1003.    begin
  1004.       FIO.Check_Write_Status (AP (File));
  1005.  
  1006.       if Item'Length > 0 then
  1007.  
  1008.          --  If we have bounded lines, then do things character by
  1009.          --  character (this seems a rare case anyway!)
  1010.  
  1011.          if File.Line_Length /= 0 then
  1012.             for J in Item'Range loop
  1013.                Put (File, Item (J));
  1014.             end loop;
  1015.  
  1016.          --  Otherwise we can output the entire string at once. Note that if
  1017.          --  there are LF or FF characters in the string, we do not bother to
  1018.          --  count them as line or page terminators.
  1019.  
  1020.          else
  1021.             FIO.Write_Buf (AP (File), Item'Address, Item'Length);
  1022.             File.Col := File.Col + Item'Length;
  1023.          end if;
  1024.       end if;
  1025.    end Put;
  1026.  
  1027.    procedure Put (Item : in String) is
  1028.    begin
  1029.       Put (Current_Out, Item);
  1030.    end Put;
  1031.  
  1032.    --------------
  1033.    -- Put_Line --
  1034.    --------------
  1035.  
  1036.    procedure Put_Line
  1037.      (File : in File_Type;
  1038.       Item : in String)
  1039.    is
  1040.    begin
  1041.       FIO.Check_Write_Status (AP (File));
  1042.  
  1043.       --  If we have bounded lines, then just do a put and a new line. In
  1044.       --  this case we will end up doing things character by character in
  1045.       --  any case, and it is a rare situation.
  1046.  
  1047.       if File.Line_Length /= 0 then
  1048.          Put (File, Item);
  1049.          New_Line (File);
  1050.          return;
  1051.       end if;
  1052.  
  1053.       --  We setup a single string that has the necessary terminators and
  1054.       --  then write it with a single call. The reason for doing this is
  1055.       --  that it gives better behavior for the use of Put_Line in multi-
  1056.       --  tasking programs, since often the OS will treat the entire put
  1057.       --  operation as an atomic operation.
  1058.  
  1059.       declare
  1060.          Ilen   : constant Natural := Item'Length;
  1061.          Buffer : String (1 .. Ilen + 2);
  1062.          Plen   : size_t;
  1063.  
  1064.       begin
  1065.          Buffer (1 .. Ilen) := Item;
  1066.          Buffer (Ilen + 1) := Character'Val (LM);
  1067.  
  1068.          if File.Page_Length /= 0
  1069.            and then File.Line > File.Page_Length
  1070.          then
  1071.             Buffer (Ilen + 2) := Character'Val (PM);
  1072.             Plen := size_t (Ilen) + 2;
  1073.             File.Line := 1;
  1074.             File.Page := File.Page + 1;
  1075.  
  1076.          else
  1077.             Plen := size_t (Ilen) + 1;
  1078.             File.Line := File.Line + 1;
  1079.          end if;
  1080.  
  1081.          FIO.Write_Buf (AP (File), Buffer'Address, Plen);
  1082.  
  1083.          File.Col := 1;
  1084.       end;
  1085.    end Put_Line;
  1086.  
  1087.    procedure Put_Line (Item : in String) is
  1088.    begin
  1089.       Put_Line (Current_Out, Item);
  1090.    end Put_Line;
  1091.  
  1092.    ----------
  1093.    -- Putc --
  1094.    ----------
  1095.  
  1096.    procedure Putc (ch : int; File : File_Type) is
  1097.    begin
  1098.       if fputc (ch, File.Stream) = EOF then
  1099.          raise Device_Error;
  1100.       end if;
  1101.    end Putc;
  1102.  
  1103.    ----------
  1104.    -- Read --
  1105.    ----------
  1106.  
  1107.    --  This is the primitive Stream Read routine, used when a Text_IO file
  1108.    --  is treated directly as a stream using Text_IO.Streams.Stream.
  1109.  
  1110.    procedure Read
  1111.      (File : in out Text_AFCB;
  1112.       Item : out Stream_Element_Array;
  1113.       Last : out Stream_Element_Offset)
  1114.    is
  1115.       ch : int;
  1116.  
  1117.    begin
  1118.       if File.Mode /= FCB.In_File then
  1119.          raise Mode_Error;
  1120.       end if;
  1121.  
  1122.       --  Deal with case where our logical and physical position do not match
  1123.       --  because of being after an LM or LM-PM sequence when in fact we are
  1124.       --  logically positioned before it.
  1125.  
  1126.       if File.Before_LM then
  1127.  
  1128.          --  If we are before a PM, then it is possible for a stream read
  1129.          --  to leave us after the LM and before the PM, which is a bit
  1130.          --  odd. The easiest way to deal with this is to unget the PM,
  1131.          --  so we are indeed positioned between the characters. This way
  1132.          --  further stream read operations will work correctly, and the
  1133.          --  effect on text processing is a little weird, but what can
  1134.          --  be expected if stream and text input are mixed this way?
  1135.  
  1136.          if File.Before_LM_PM then
  1137.             ch := ungetc (PM, File.Stream);
  1138.             File.Before_LM_PM := False;
  1139.          end if;
  1140.  
  1141.          File.Before_LM := False;
  1142.  
  1143.          Item (Item'First) := Stream_Element (Character'Pos (ASCII.LF));
  1144.  
  1145.          if Item'Length = 1 then
  1146.             Last := Item'Last;
  1147.  
  1148.          else
  1149.             Last :=
  1150.               Item'First +
  1151.                 Stream_Element_Offset
  1152.                   (fread (buffer => Item'Address,
  1153.                           index  => size_t (Item'First + 1),
  1154.                           size   => 1,
  1155.                           count  => Item'Length - 1,
  1156.                           stream => File.Stream));
  1157.          end if;
  1158.  
  1159.          return;
  1160.       end if;
  1161.  
  1162.       --  Now we do the read. Since this is a text file, it is normally in
  1163.       --  text mode, but stream data must be read in binary mode, so we
  1164.       --  temporarily set binary mode for the read, resetting it after.
  1165.       --  These calls have no effect in a system (like Unix) where there is
  1166.       --  no distinction between text and binary files.
  1167.  
  1168.       set_binary_mode (fileno (File.Stream));
  1169.  
  1170.       Last :=
  1171.         Item'First +
  1172.           Stream_Element_Offset
  1173.             (fread (Item'Address, 1, Item'Length, File.Stream)) - 1;
  1174.  
  1175.       if Last < Item'Last then
  1176.          if ferror (File.Stream) /= 0 then
  1177.             raise Device_Error;
  1178.          end if;
  1179.       end if;
  1180.  
  1181.       set_text_mode (fileno (File.Stream));
  1182.    end Read;
  1183.  
  1184.    -----------
  1185.    -- Reset --
  1186.    -----------
  1187.  
  1188.    procedure Reset
  1189.      (File : in out File_Type;
  1190.       Mode : in File_Mode)
  1191.    is
  1192.    begin
  1193.       --  Don't allow change of mode for current file (RM A.10.2(5))
  1194.  
  1195.       if (File = Current_In or else
  1196.           File = Current_Out  or else
  1197.           File = Current_Error)
  1198.         and then To_FCB (Mode) /= File.Mode
  1199.       then
  1200.          raise Mode_Error;
  1201.       end if;
  1202.  
  1203.       Terminate_Line (File);
  1204.       FIO.Reset (AP (File), To_FCB (Mode));
  1205.       File.Page := 1;
  1206.       File.Line := 1;
  1207.       File.Col  := 1;
  1208.       File.Line_Length := 0;
  1209.       File.Page_Length := 0;
  1210.       File.Before_LM := False;
  1211.       File.Before_LM_PM := False;
  1212.    end Reset;
  1213.  
  1214.    procedure Reset (File : in out File_Type) is
  1215.    begin
  1216.       Terminate_Line (File);
  1217.       FIO.Reset (AP (File));
  1218.       File.Page := 1;
  1219.       File.Line := 1;
  1220.       File.Col  := 1;
  1221.       File.Line_Length := 0;
  1222.       File.Page_Length := 0;
  1223.       File.Before_LM := False;
  1224.       File.Before_LM_PM := False;
  1225.    end Reset;
  1226.  
  1227.    -------------
  1228.    -- Set_Col --
  1229.    -------------
  1230.  
  1231.    procedure Set_Col
  1232.      (File : in File_Type;
  1233.       To   : in Positive_Count)
  1234.    is
  1235.       ch : int;
  1236.  
  1237.    begin
  1238.       --  Raise Constraint_Error if out of range value. The reason for this
  1239.       --  explicit test is that we don't want junk values around, even if
  1240.       --  checks are off in the caller.
  1241.  
  1242.       if To not in Positive_Count then
  1243.          raise Constraint_Error;
  1244.       end if;
  1245.  
  1246.       FIO.Check_File_Open (AP (File));
  1247.  
  1248.       if To = File.Col then
  1249.          return;
  1250.       end if;
  1251.  
  1252.       if Mode (File) >= Out_File then
  1253.          if File.Line_Length /= 0 and then To > File.Line_Length then
  1254.             raise Layout_Error;
  1255.          end if;
  1256.  
  1257.          if To < File.Col then
  1258.             New_Line (File);
  1259.          end if;
  1260.  
  1261.          while File.Col < To loop
  1262.             Put (File, ' ');
  1263.          end loop;
  1264.  
  1265.       else
  1266.          loop
  1267.             ch := Getc (File);
  1268.  
  1269.             if ch = EOF then
  1270.                raise End_Error;
  1271.  
  1272.             elsif ch = LM then
  1273.                File.Line := File.Line + 1;
  1274.                File.Col := 1;
  1275.  
  1276.             elsif ch = PM and then File.Is_Regular_File then
  1277.                File.Page := File.Page + 1;
  1278.                File.Line := 1;
  1279.                File.Col := 1;
  1280.  
  1281.             elsif To = File.Col then
  1282.                Ungetc (ch, File);
  1283.                return;
  1284.  
  1285.             else
  1286.                File.Col := File.Col + 1;
  1287.             end if;
  1288.          end loop;
  1289.       end if;
  1290.    end Set_Col;
  1291.  
  1292.    procedure Set_Col (To : in Positive_Count) is
  1293.    begin
  1294.       Set_Col (Current_Out, To);
  1295.    end Set_Col;
  1296.  
  1297.    ---------------
  1298.    -- Set_Error --
  1299.    ---------------
  1300.  
  1301.    procedure Set_Error (File : in File_Type) is
  1302.    begin
  1303.       FIO.Check_Write_Status (AP (File));
  1304.       Current_Err := File;
  1305.    end Set_Error;
  1306.  
  1307.    ---------------
  1308.    -- Set_Input --
  1309.    ---------------
  1310.  
  1311.    procedure Set_Input (File : in File_Type) is
  1312.    begin
  1313.       FIO.Check_Read_Status (AP (File));
  1314.       Current_In := File;
  1315.    end Set_Input;
  1316.  
  1317.    --------------
  1318.    -- Set_Line --
  1319.    --------------
  1320.  
  1321.    procedure Set_Line
  1322.      (File : in File_Type;
  1323.       To   : in Positive_Count)
  1324.    is
  1325.    begin
  1326.       --  Raise Constraint_Error if out of range value. The reason for this
  1327.       --  explicit test is that we don't want junk values around, even if
  1328.       --  checks are off in the caller.
  1329.  
  1330.       if To not in Positive_Count then
  1331.          raise Constraint_Error;
  1332.       end if;
  1333.  
  1334.       FIO.Check_File_Open (AP (File));
  1335.  
  1336.       if To = File.Line then
  1337.          return;
  1338.       end if;
  1339.  
  1340.       if Mode (File) >= Out_File then
  1341.          if File.Page_Length /= 0 and then To > File.Page_Length then
  1342.             raise Layout_Error;
  1343.          end if;
  1344.  
  1345.          if To < File.Line then
  1346.             New_Page (File);
  1347.          end if;
  1348.  
  1349.          while File.Line < To loop
  1350.             New_Line (File);
  1351.          end loop;
  1352.  
  1353.       else
  1354.          while To /= File.Line loop
  1355.             Skip_Line (File);
  1356.          end loop;
  1357.       end if;
  1358.    end Set_Line;
  1359.  
  1360.    procedure Set_Line (To : in Positive_Count) is
  1361.    begin
  1362.       Set_Line (Current_Out, To);
  1363.    end Set_Line;
  1364.  
  1365.    ---------------------
  1366.    -- Set_Line_Length --
  1367.    ---------------------
  1368.  
  1369.    procedure Set_Line_Length (File : in File_Type; To : in Count) is
  1370.    begin
  1371.       --  Raise Constraint_Error if out of range value. The reason for this
  1372.       --  explicit test is that we don't want junk values around, even if
  1373.       --  checks are off in the caller.
  1374.  
  1375.       if To not in Count then
  1376.          raise Constraint_Error;
  1377.       end if;
  1378.  
  1379.       FIO.Check_Write_Status (AP (File));
  1380.       File.Line_Length := To;
  1381.    end Set_Line_Length;
  1382.  
  1383.    procedure Set_Line_Length (To : in Count) is
  1384.    begin
  1385.       Set_Line_Length (Current_Out, To);
  1386.    end Set_Line_Length;
  1387.  
  1388.    ----------------
  1389.    -- Set_Output --
  1390.    ----------------
  1391.  
  1392.    procedure Set_Output (File : in File_Type) is
  1393.    begin
  1394.       FIO.Check_Write_Status (AP (File));
  1395.       Current_Out := File;
  1396.    end Set_Output;
  1397.  
  1398.    ---------------------
  1399.    -- Set_Page_Length --
  1400.    ---------------------
  1401.  
  1402.    procedure Set_Page_Length (File : in File_Type; To : in Count) is
  1403.    begin
  1404.       --  Raise Constraint_Error if out of range value. The reason for this
  1405.       --  explicit test is that we don't want junk values around, even if
  1406.       --  checks are off in the caller.
  1407.  
  1408.       if To not in Count then
  1409.          raise Constraint_Error;
  1410.       end if;
  1411.  
  1412.       FIO.Check_Write_Status (AP (File));
  1413.       File.Page_Length := To;
  1414.    end Set_Page_Length;
  1415.  
  1416.    procedure Set_Page_Length (To : in Count) is
  1417.    begin
  1418.       Set_Page_Length (Current_Out, To);
  1419.    end Set_Page_Length;
  1420.  
  1421.    ---------------
  1422.    -- Skip_Line --
  1423.    ---------------
  1424.  
  1425.    procedure Skip_Line
  1426.      (File    : in File_Type;
  1427.       Spacing : in Positive_Count := 1)
  1428.    is
  1429.       ch : int;
  1430.  
  1431.    begin
  1432.       --  Raise Constraint_Error if out of range value. The reason for this
  1433.       --  explicit test is that we don't want junk values around, even if
  1434.       --  checks are off in the caller.
  1435.  
  1436.       if Spacing not in Positive_Count then
  1437.          raise Constraint_Error;
  1438.       end if;
  1439.  
  1440.       FIO.Check_Read_Status (AP (File));
  1441.  
  1442.       for L in 1 .. Spacing loop
  1443.          if File.Before_LM then
  1444.             File.Before_LM := False;
  1445.             File.Before_LM_PM := False;
  1446.  
  1447.          else
  1448.             ch := Getc (File);
  1449.  
  1450.             --  If at end of file now, then immediately raise End_Error. Note
  1451.             --  that we can never be positioned between a line mark and a page
  1452.             --  mark, so if we are at the end of file, we cannot logically be
  1453.             --  before the implicit page mark that is at the end of the file.
  1454.  
  1455.             --  For the same reason, we do not need an explicit check for a
  1456.             --  page mark. If there is a FF in the middle of a line, the file
  1457.             --  is not in canonical format and we do not care about the page
  1458.             --  numbers for files other than ones in canonical format.
  1459.  
  1460.             if ch = EOF then
  1461.                raise End_Error;
  1462.             end if;
  1463.  
  1464.             --  If not at end of file, then loop till we get to an LM or EOF.
  1465.             --  The latter case happens only in non-canonical files where the
  1466.             --  last line is not terminated by LM, but we don't want to blow
  1467.             --  up for such files, so we assume an implicit LM in this case.
  1468.  
  1469.             loop
  1470.                exit when ch = LM or ch = EOF;
  1471.                ch := Getc (File);
  1472.             end loop;
  1473.          end if;
  1474.  
  1475.          --  We have got past a line mark, now, for a regular file only,
  1476.          --  see if a page mark immediately follows this line mark and
  1477.          --  if so, skip past the page mark as well. We do not do this
  1478.          --  for non-regular files, since it would cause an undesirable
  1479.          --  wait for an additional character.
  1480.  
  1481.          File.Col := 1;
  1482.          File.Line := File.Line + 1;
  1483.  
  1484.          if File.Before_LM_PM then
  1485.             File.Page := File.Page + 1;
  1486.             File.Line := 1;
  1487.             File.Before_LM_PM := False;
  1488.  
  1489.          elsif File.Is_Regular_File then
  1490.             ch := Getc (File);
  1491.  
  1492.             --  Page mark can be explicit, or implied at the end of the file
  1493.  
  1494.             if (ch = PM or else ch = EOF)
  1495.               and then File.Is_Regular_File
  1496.             then
  1497.                File.Page := File.Page + 1;
  1498.                File.Line := 1;
  1499.             else
  1500.                Ungetc (ch, File);
  1501.             end if;
  1502.          end if;
  1503.  
  1504.       end loop;
  1505.    end Skip_Line;
  1506.  
  1507.    procedure Skip_Line (Spacing : in Positive_Count := 1) is
  1508.    begin
  1509.       Skip_Line (Current_In, Spacing);
  1510.    end Skip_Line;
  1511.  
  1512.    ---------------
  1513.    -- Skip_Page --
  1514.    ---------------
  1515.  
  1516.    procedure Skip_Page (File : in File_Type) is
  1517.       ch : int;
  1518.  
  1519.    begin
  1520.       FIO.Check_Read_Status (AP (File));
  1521.  
  1522.       --  If at page mark already, just skip it
  1523.  
  1524.       if File.Before_LM_PM then
  1525.          File.Before_LM := False;
  1526.          File.Before_LM_PM := False;
  1527.          File.Page := File.Page + 1;
  1528.          File.Line := 1;
  1529.          File.Col  := 1;
  1530.          return;
  1531.       end if;
  1532.  
  1533.       --  This is a bit tricky, if we are logically before an LM then
  1534.       --  it is not an error if we are at an end of file now, since we
  1535.       --  are not really at it.
  1536.  
  1537.       if File.Before_LM then
  1538.          File.Before_LM := False;
  1539.          File.Before_LM_PM := False;
  1540.          ch := Getc (File);
  1541.  
  1542.       --  Otherwise we do raise End_Error if we are at the end of file now
  1543.  
  1544.       else
  1545.          ch := Getc (File);
  1546.  
  1547.          if ch = EOF then
  1548.             raise End_Error;
  1549.          end if;
  1550.       end if;
  1551.  
  1552.       --  Now we can just rumble along to the next page mark, or to the
  1553.       --  end of file, if that comes first. The latter case happens when
  1554.       --  the page mark is implied at the end of file.
  1555.  
  1556.       loop
  1557.          exit when ch = EOF
  1558.            or else (ch = PM and then File.Is_Regular_File);
  1559.          ch := Getc (File);
  1560.       end loop;
  1561.  
  1562.       File.Page := File.Page + 1;
  1563.       File.Line := 1;
  1564.       File.Col  := 1;
  1565.    end Skip_Page;
  1566.  
  1567.    procedure Skip_Page is
  1568.    begin
  1569.       Skip_Page (Current_In);
  1570.    end Skip_Page;
  1571.  
  1572.    --------------------
  1573.    -- Standard_Error --
  1574.    --------------------
  1575.  
  1576.    function Standard_Error return File_Type is
  1577.    begin
  1578.       return Standard_Err;
  1579.    end Standard_Error;
  1580.  
  1581.    function Standard_Error return File_Access is
  1582.    begin
  1583.       return Standard_Err'Access;
  1584.    end Standard_Error;
  1585.  
  1586.    --------------------
  1587.    -- Standard_Input --
  1588.    --------------------
  1589.  
  1590.    function Standard_Input return File_Type is
  1591.    begin
  1592.       return Standard_In;
  1593.    end Standard_Input;
  1594.  
  1595.    function Standard_Input return File_Access is
  1596.    begin
  1597.       return Standard_In'Access;
  1598.    end Standard_Input;
  1599.  
  1600.    ---------------------
  1601.    -- Standard_Output --
  1602.    ---------------------
  1603.  
  1604.    function Standard_Output return File_Type is
  1605.    begin
  1606.       return Standard_Out;
  1607.    end Standard_Output;
  1608.  
  1609.    function Standard_Output return File_Access is
  1610.    begin
  1611.       return Standard_Out'Access;
  1612.    end Standard_Output;
  1613.  
  1614.    --------------------
  1615.    -- Terminate_Line --
  1616.    --------------------
  1617.  
  1618.    procedure Terminate_Line (File : File_Type) is
  1619.    begin
  1620.       FIO.Check_File_Open (AP (File));
  1621.  
  1622.       --  For file other than In_File, test for needing to terminate last line
  1623.  
  1624.       if Mode (File) /= In_File then
  1625.  
  1626.          --  If not at start of line definition need new line
  1627.  
  1628.          if File.Col /= 1 then
  1629.             New_Line (File);
  1630.  
  1631.          --  For files other than standard error and standard output, we
  1632.          --  make sure that an empty file has a single line feed, so that
  1633.          --  it is properly formatted. We avoid this for the standard files
  1634.          --  because it is too much of a nuisance to have these odd line
  1635.          --  feeds when nothing has been written to the file.
  1636.  
  1637.          elsif (File /= Standard_Err and then File /= Standard_Out)
  1638.            and then (File.Line = 1 and then File.Page = 1)
  1639.          then
  1640.             New_Line (File);
  1641.          end if;
  1642.       end if;
  1643.    end Terminate_Line;
  1644.  
  1645.    ------------
  1646.    -- Ungetc --
  1647.    ------------
  1648.  
  1649.    procedure Ungetc (ch : int; File : File_Type) is
  1650.    begin
  1651.       if ch /= EOF then
  1652.          if ungetc (ch, File.Stream) = EOF then
  1653.             raise Device_Error;
  1654.          end if;
  1655.       end if;
  1656.    end Ungetc;
  1657.  
  1658.    -----------
  1659.    -- Write --
  1660.    -----------
  1661.  
  1662.    --  This is the primitive Stream Write routine, used when a Text_IO file
  1663.    --  is treated directly as a stream using Text_IO.Streams.Stream.
  1664.  
  1665.    procedure Write
  1666.      (File : in out Text_AFCB;
  1667.       Item : in Stream_Element_Array)
  1668.    is
  1669.       Siz : constant size_t := Item'Length;
  1670.  
  1671.    begin
  1672.       if File.Mode = FCB.In_File then
  1673.          raise Mode_Error;
  1674.       end if;
  1675.  
  1676.       --  Now we do the write. Since this is a text file, it is normally in
  1677.       --  text mode, but stream data must be written in binary mode, so we
  1678.       --  temporarily set binary mode for the write, resetting it after.
  1679.       --  These calls have no effect in a system (like Unix) where there is
  1680.       --  no distinction between text and binary files.
  1681.  
  1682.       set_binary_mode (fileno (File.Stream));
  1683.  
  1684.       if fwrite (Item'Address, 1, Siz, File.Stream) /= Siz then
  1685.          raise Device_Error;
  1686.       end if;
  1687.  
  1688.       set_text_mode (fileno (File.Stream));
  1689.    end Write;
  1690.  
  1691.    --  Use "preallocated" strings to avoid calling "new" during the
  1692.    --  elaboration of the run time. This is needed is the tasking case to
  1693.    --  avoid calling Task_Lock too early.
  1694.  
  1695.    Err_Name : aliased String := "*stderr";
  1696.    In_Name  : aliased String := "*stdin";
  1697.    Out_Name : aliased String := "*stdout";
  1698. begin
  1699.    -------------------------------
  1700.    -- Initialize Standard Files --
  1701.    -------------------------------
  1702.  
  1703.    --  Note: the names in these files are bogus, and probably it would be
  1704.    --  better for these files to have no names, but the ACVC test insist!
  1705.    --  We use names that are bound to fail in open etc.
  1706.  
  1707.  
  1708.    Standard_Err.Stream            := stderr;
  1709.    Standard_Err.Name              := Err_Name'Access;
  1710.    Standard_Err.Form              := Null_Str'Unrestricted_Access;
  1711.    Standard_Err.Mode              := FCB.Out_File;
  1712.    Standard_Err.Is_Regular_File   := is_regular_file (fileno (stderr)) /= 0;
  1713.    Standard_Err.Is_Temporary_File := False;
  1714.    Standard_Err.Is_System_File    := True;
  1715.    Standard_Err.Is_Text_File      := True;
  1716.    Standard_Err.Access_Method     := 'T';
  1717.    Standard_Err.Self              := Standard_Err;
  1718.  
  1719.    Standard_In.Stream             := stdin;
  1720.    Standard_In.Name               := In_Name'Access;
  1721.    Standard_In.Form               := Null_Str'Unrestricted_Access;
  1722.    Standard_In.Mode               := FCB.In_File;
  1723.    Standard_In.Is_Regular_File    := is_regular_file (fileno (stdin)) /= 0;
  1724.    Standard_In.Is_Temporary_File  := False;
  1725.    Standard_In.Is_System_File     := True;
  1726.    Standard_In.Is_Text_File       := True;
  1727.    Standard_In.Access_Method      := 'T';
  1728.    Standard_In.Self               := Standard_In;
  1729.  
  1730.    Standard_Out.Stream            := stdout;
  1731.    Standard_Out.Name              := Out_Name'Access;
  1732.    Standard_Out.Form              := Null_Str'Unrestricted_Access;
  1733.    Standard_Out.Mode              := FCB.Out_File;
  1734.    Standard_Out.Is_Regular_File   := is_regular_file (fileno (stdout)) /= 0;
  1735.    Standard_Out.Is_Temporary_File := False;
  1736.    Standard_Out.Is_System_File    := True;
  1737.    Standard_Out.Is_Text_File      := True;
  1738.    Standard_Out.Access_Method     := 'T';
  1739.    Standard_Out.Self              := Standard_Out;
  1740.  
  1741.    FIO.Chain_File (AP (Standard_In));
  1742.    FIO.Chain_File (AP (Standard_Out));
  1743.    FIO.Chain_File (AP (Standard_Err));
  1744.  
  1745.    FIO.Make_Unbuffered (AP (Standard_Out));
  1746.    FIO.Make_Unbuffered (AP (Standard_Err));
  1747.  
  1748. end Ada.Text_IO;
  1749.