OSDN Git Service

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