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-witeio.adb < prev    next >
Text File  |  2000-07-19  |  48KB  |  1,814 lines

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