i386: Adjust rtx cost for imulq and imulw [PR115749]
[official-gcc.git] / gcc / ada / libgnat / a-witeio.adb
blobe72bcc0d5a204db2a8b8603c58f334a9e7d0484c
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-2024, 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 3, 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. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 with Ada.Streams; use Ada.Streams;
33 with Interfaces.C_Streams; use Interfaces.C_Streams;
35 with System.CRTL;
36 with System.File_IO;
37 with System.WCh_Cnv; use System.WCh_Cnv;
38 with System.WCh_Con; use System.WCh_Con;
40 with Ada.Unchecked_Conversion;
41 with Ada.Unchecked_Deallocation;
43 pragma Elaborate_All (System.File_IO);
44 -- Needed because of calls to Chain_File in package body elaboration
46 package body Ada.Wide_Text_IO is
48 package FIO renames System.File_IO;
50 subtype AP is FCB.AFCB_Ptr;
52 function To_FCB is new Ada.Unchecked_Conversion (File_Mode, FCB.File_Mode);
53 function To_TIO is new Ada.Unchecked_Conversion (FCB.File_Mode, File_Mode);
54 use type FCB.File_Mode;
56 use type System.CRTL.size_t;
58 WC_Encoding : constant Character;
59 pragma Import (C, WC_Encoding, "__gl_wc_encoding");
60 -- Default wide character encoding
62 Err_Name : aliased String := "*stderr" & ASCII.NUL;
63 In_Name : aliased String := "*stdin" & ASCII.NUL;
64 Out_Name : aliased String := "*stdout" & ASCII.NUL;
65 -- Names of standard files
67 -- Use "preallocated" strings to avoid calling "new" during the elaboration
68 -- of the run time. This is needed in the tasking case to avoid calling
69 -- Task_Lock too early. A filename is expected to end with a null character
70 -- in the runtime, here the null characters are added just to have a
71 -- correct filename length.
73 -- Note: the names for these files are bogus, and probably it would be
74 -- better for these files to have no names, but the ACVC tests insist.
75 -- We use names that are bound to fail in open etc.
77 Null_Str : aliased constant String := "";
78 -- Used as form string for standard files
80 -----------------------
81 -- Local Subprograms --
82 -----------------------
84 function Get_Wide_Char_Immed
85 (C : Character;
86 File : File_Type) return Wide_Character;
87 -- This routine is identical to Get_Wide_Char, except that the reads are
88 -- done in Get_Immediate mode (i.e. without waiting for a line return).
90 function Getc_Immed (File : File_Type) return int;
91 -- This routine is identical to Getc, except that the read is done in
92 -- Get_Immediate mode (i.e. without waiting for a line return).
94 procedure Putc (ch : int; File : File_Type);
95 -- Outputs the given character to the file, which has already been checked
96 -- for being in output status. Device_Error is raised if the character
97 -- cannot be written.
99 procedure Set_WCEM (File : in out File_Type);
100 -- Called by Open and Create to set the wide character encoding method for
101 -- the file, processing a WCEM form parameter if one is present. File is
102 -- IN OUT because it may be closed in case of an error.
104 procedure Terminate_Line (File : File_Type);
105 -- If the file is in Write_File or Append_File mode, and the current line
106 -- is not terminated, then a line terminator is written using New_Line.
107 -- Note that there is no Terminate_Page routine, because the page mark at
108 -- the end of the file is implied if necessary.
110 procedure Ungetc (ch : int; File : File_Type);
111 -- Pushes back character into stream, using ungetc. The caller has checked
112 -- that the file is in read status. Device_Error is raised if the character
113 -- cannot be pushed back. An attempt to push back and end of file character
114 -- (EOF) is ignored.
116 -------------------
117 -- AFCB_Allocate --
118 -------------------
120 function AFCB_Allocate
121 (Control_Block : Wide_Text_AFCB) return FCB.AFCB_Ptr
123 pragma Unreferenced (Control_Block);
124 begin
125 return new Wide_Text_AFCB;
126 end AFCB_Allocate;
128 ----------------
129 -- AFCB_Close --
130 ----------------
132 procedure AFCB_Close (File : not null access Wide_Text_AFCB) is
133 begin
134 -- If the file being closed is one of the current files, then close
135 -- the corresponding current file. It is not clear that this action
136 -- is required (RM A.10.3(23)) but it seems reasonable, and besides
137 -- ACVC test CE3208A expects this behavior.
139 if File = Current_In then
140 Current_In := null;
141 elsif File = Current_Out then
142 Current_Out := null;
143 elsif File = Current_Err then
144 Current_Err := null;
145 end if;
147 Terminate_Line (File.all'Access);
148 end AFCB_Close;
150 ---------------
151 -- AFCB_Free --
152 ---------------
154 procedure AFCB_Free (File : not null access Wide_Text_AFCB) is
155 FT : File_Type := File.all'Access;
157 procedure Free is
158 new Ada.Unchecked_Deallocation (Wide_Text_AFCB, File_Type);
160 begin
161 Free (FT);
162 end AFCB_Free;
164 -----------
165 -- Close --
166 -----------
168 procedure Close (File : in out File_Type) is
169 begin
170 FIO.Close (AP (File)'Unrestricted_Access);
171 end Close;
173 ---------
174 -- Col --
175 ---------
177 -- Note: we assume that it is impossible in practice for the column
178 -- to exceed the value of Count'Last, i.e. no check is required for
179 -- overflow raising layout error.
181 function Col (File : File_Type) return Positive_Count is
182 begin
183 FIO.Check_File_Open (AP (File));
184 return File.Col;
185 end Col;
187 function Col return Positive_Count is
188 begin
189 return Col (Current_Out);
190 end Col;
192 ------------
193 -- Create --
194 ------------
196 procedure Create
197 (File : in out File_Type;
198 Mode : File_Mode := Out_File;
199 Name : String := "";
200 Form : String := "")
202 Dummy_File_Control_Block : Wide_Text_AFCB;
203 pragma Warnings (Off, Dummy_File_Control_Block);
204 -- Yes, we know this is never assigned a value, only the tag
205 -- is used for dispatching purposes, so that's expected.
207 begin
208 FIO.Open (File_Ptr => AP (File),
209 Dummy_FCB => Dummy_File_Control_Block,
210 Mode => To_FCB (Mode),
211 Name => Name,
212 Form => Form,
213 Amethod => 'W',
214 Creat => True,
215 Text => True);
217 File.Self := File;
218 Set_WCEM (File);
219 end Create;
221 -------------------
222 -- Current_Error --
223 -------------------
225 function Current_Error return File_Type is
226 begin
227 return Current_Err;
228 end Current_Error;
230 function Current_Error return File_Access is
231 begin
232 return Current_Err.Self'Access;
233 end Current_Error;
235 -------------------
236 -- Current_Input --
237 -------------------
239 function Current_Input return File_Type is
240 begin
241 return Current_In;
242 end Current_Input;
244 function Current_Input return File_Access is
245 begin
246 return Current_In.Self'Access;
247 end Current_Input;
249 --------------------
250 -- Current_Output --
251 --------------------
253 function Current_Output return File_Type is
254 begin
255 return Current_Out;
256 end Current_Output;
258 function Current_Output return File_Access is
259 begin
260 return Current_Out.Self'Access;
261 end Current_Output;
263 ------------
264 -- Delete --
265 ------------
267 procedure Delete (File : in out File_Type) is
268 begin
269 FIO.Delete (AP (File)'Unrestricted_Access);
270 end Delete;
272 -----------------
273 -- End_Of_File --
274 -----------------
276 function End_Of_File (File : File_Type) return Boolean is
277 ch : int;
279 begin
280 FIO.Check_Read_Status (AP (File));
282 if File.Before_Wide_Character then
283 return False;
285 elsif File.Before_LM then
286 if File.Before_LM_PM then
287 return Nextc (File) = EOF;
288 end if;
290 else
291 ch := Getc (File);
293 if ch = EOF then
294 return True;
296 elsif ch /= LM then
297 Ungetc (ch, File);
298 return False;
300 else -- ch = LM
301 File.Before_LM := True;
302 end if;
303 end if;
305 -- Here we are just past the line mark with Before_LM set so that we
306 -- do not have to try to back up past the LM, thus avoiding the need
307 -- to back up more than one character.
309 ch := Getc (File);
311 if ch = EOF then
312 return True;
314 elsif ch = PM and then File.Is_Regular_File then
315 File.Before_LM_PM := True;
316 return Nextc (File) = EOF;
318 -- Here if neither EOF nor PM followed end of line
320 else
321 Ungetc (ch, File);
322 return False;
323 end if;
325 end End_Of_File;
327 function End_Of_File return Boolean is
328 begin
329 return End_Of_File (Current_In);
330 end End_Of_File;
332 -----------------
333 -- End_Of_Line --
334 -----------------
336 function End_Of_Line (File : File_Type) return Boolean is
337 ch : int;
339 begin
340 FIO.Check_Read_Status (AP (File));
342 if File.Before_Wide_Character then
343 return False;
345 elsif File.Before_LM then
346 return True;
348 else
349 ch := Getc (File);
351 if ch = EOF then
352 return True;
354 else
355 Ungetc (ch, File);
356 return (ch = LM);
357 end if;
358 end if;
359 end End_Of_Line;
361 function End_Of_Line return Boolean is
362 begin
363 return End_Of_Line (Current_In);
364 end End_Of_Line;
366 -----------------
367 -- End_Of_Page --
368 -----------------
370 function End_Of_Page (File : File_Type) return Boolean is
371 ch : int;
373 begin
374 FIO.Check_Read_Status (AP (File));
376 if not File.Is_Regular_File then
377 return False;
379 elsif File.Before_Wide_Character then
380 return False;
382 elsif File.Before_LM then
383 if File.Before_LM_PM then
384 return True;
385 end if;
387 else
388 ch := Getc (File);
390 if ch = EOF then
391 return True;
393 elsif ch /= LM then
394 Ungetc (ch, File);
395 return False;
397 else -- ch = LM
398 File.Before_LM := True;
399 end if;
400 end if;
402 -- Here we are just past the line mark with Before_LM set so that we
403 -- do not have to try to back up past the LM, thus avoiding the need
404 -- to back up more than one character.
406 ch := Nextc (File);
408 return ch = PM or else ch = EOF;
409 end End_Of_Page;
411 function End_Of_Page return Boolean is
412 begin
413 return End_Of_Page (Current_In);
414 end End_Of_Page;
416 -----------
417 -- Flush --
418 -----------
420 procedure Flush (File : File_Type) is
421 begin
422 FIO.Flush (AP (File));
423 end Flush;
425 procedure Flush is
426 begin
427 Flush (Current_Out);
428 end Flush;
430 ----------
431 -- Form --
432 ----------
434 function Form (File : File_Type) return String is
435 begin
436 return FIO.Form (AP (File));
437 end Form;
439 ---------
440 -- Get --
441 ---------
443 procedure Get
444 (File : File_Type;
445 Item : out Wide_Character)
447 C : Character;
449 begin
450 FIO.Check_Read_Status (AP (File));
452 if File.Before_Wide_Character then
453 File.Before_Wide_Character := False;
454 Item := File.Saved_Wide_Character;
456 -- Ada.Text_IO checks Before_LM_PM here, shouldn't we do the same???
458 else
459 Get_Character (File, C);
460 Item := Get_Wide_Char (C, File);
461 end if;
462 end Get;
464 procedure Get (Item : out Wide_Character) is
465 begin
466 Get (Current_In, Item);
467 end Get;
469 procedure Get
470 (File : File_Type;
471 Item : out Wide_String)
473 begin
474 for J in Item'Range loop
475 Get (File, Item (J));
476 end loop;
477 end Get;
479 procedure Get (Item : out Wide_String) is
480 begin
481 Get (Current_In, Item);
482 end Get;
484 -------------------
485 -- Get_Character --
486 -------------------
488 procedure Get_Character
489 (File : File_Type;
490 Item : out Character)
492 ch : int;
494 begin
495 if File.Before_LM then
496 File.Before_LM := False;
497 File.Before_LM_PM := False;
498 File.Col := 1;
500 if File.Before_LM_PM then
501 File.Line := 1;
502 File.Page := File.Page + 1;
503 File.Before_LM_PM := False;
505 else
506 File.Line := File.Line + 1;
507 end if;
508 end if;
510 loop
511 ch := Getc (File);
513 if ch = EOF then
514 raise End_Error;
516 elsif ch = LM then
517 File.Line := File.Line + 1;
518 File.Col := 1;
520 elsif ch = PM and then File.Is_Regular_File then
521 File.Page := File.Page + 1;
522 File.Line := 1;
524 else
525 Item := Character'Val (ch);
526 File.Col := File.Col + 1;
527 return;
528 end if;
529 end loop;
530 end Get_Character;
532 -------------------
533 -- Get_Immediate --
534 -------------------
536 procedure Get_Immediate
537 (File : File_Type;
538 Item : out Wide_Character)
540 ch : int;
542 begin
543 FIO.Check_Read_Status (AP (File));
545 if File.Before_Wide_Character then
546 File.Before_Wide_Character := False;
547 Item := File.Saved_Wide_Character;
549 elsif File.Before_LM then
550 File.Before_LM := False;
551 File.Before_LM_PM := False;
552 Item := Wide_Character'Val (LM);
554 else
555 ch := Getc_Immed (File);
557 if ch = EOF then
558 raise End_Error;
559 else
560 Item := Get_Wide_Char_Immed (Character'Val (ch), File);
561 end if;
562 end if;
563 end Get_Immediate;
565 procedure Get_Immediate
566 (Item : out Wide_Character)
568 begin
569 Get_Immediate (Current_In, Item);
570 end Get_Immediate;
572 procedure Get_Immediate
573 (File : File_Type;
574 Item : out Wide_Character;
575 Available : out Boolean)
577 ch : int;
579 begin
580 FIO.Check_Read_Status (AP (File));
581 Available := True;
583 if File.Before_Wide_Character then
584 File.Before_Wide_Character := False;
585 Item := File.Saved_Wide_Character;
587 elsif File.Before_LM then
588 File.Before_LM := False;
589 File.Before_LM_PM := False;
590 Item := Wide_Character'Val (LM);
592 else
593 -- Shouldn't we use getc_immediate_nowait here, like Text_IO???
595 ch := Getc_Immed (File);
597 if ch = EOF then
598 raise End_Error;
599 else
600 Item := Get_Wide_Char_Immed (Character'Val (ch), File);
601 end if;
602 end if;
603 end Get_Immediate;
605 procedure Get_Immediate
606 (Item : out Wide_Character;
607 Available : out Boolean)
609 begin
610 Get_Immediate (Current_In, Item, Available);
611 end Get_Immediate;
613 --------------
614 -- Get_Line --
615 --------------
617 procedure Get_Line
618 (File : File_Type;
619 Item : out Wide_String;
620 Last : out Natural)
622 begin
623 FIO.Check_Read_Status (AP (File));
624 Last := Item'First - 1;
626 -- Immediate exit for null string, this is a case in which we do not
627 -- need to test for end of file and we do not skip a line mark under
628 -- any circumstances.
630 if Last >= Item'Last then
631 return;
632 end if;
634 -- Here we have at least one character, if we are immediately before
635 -- a line mark, then we will just skip past it storing no characters.
637 if File.Before_LM then
638 File.Before_LM := False;
639 File.Before_LM_PM := False;
641 -- Otherwise we need to read some characters
643 else
644 -- If we are at the end of file now, it means we are trying to
645 -- skip a file terminator and we raise End_Error (RM A.10.7(20))
647 if Nextc (File) = EOF then
648 raise End_Error;
649 end if;
651 -- Loop through characters in string
653 loop
654 -- Exit the loop if read is terminated by encountering line mark
655 -- Note that the use of Skip_Line here ensures we properly deal
656 -- with setting the page and line numbers.
658 if End_Of_Line (File) then
659 Skip_Line (File);
660 return;
661 end if;
663 -- Otherwise store the character, note that we know that ch is
664 -- something other than LM or EOF. It could possibly be a page
665 -- mark if there is a stray page mark in the middle of a line, but
666 -- this is not an official page mark in any case, since official
667 -- page marks can only follow a line mark. The whole page business
668 -- is pretty much nonsense anyway, so we do not want to waste
669 -- time trying to make sense out of non-standard page marks in
670 -- the file. This means that the behavior of Get_Line is different
671 -- from repeated Get of a character, but that's too bad. We
672 -- only promise that page numbers etc make sense if the file
673 -- is formatted in a standard manner.
675 -- Note: we do not adjust the column number because it is quicker
676 -- to adjust it once at the end of the operation than incrementing
677 -- it each time around the loop.
679 Last := Last + 1;
680 Get (File, Item (Last));
682 -- All done if the string is full, this is the case in which
683 -- we do not skip the following line mark. We need to adjust
684 -- the column number in this case.
686 if Last = Item'Last then
687 File.Col := File.Col + Count (Item'Length);
688 return;
689 end if;
691 -- Exit from the loop if we are at the end of file. This happens
692 -- if we have a last line that is not terminated with a line mark.
693 -- In this case we consider that there is an implied line mark;
694 -- this is a non-standard file, but we will treat it nicely.
696 exit when Nextc (File) = EOF;
697 end loop;
698 end if;
699 end Get_Line;
701 procedure Get_Line
702 (Item : out Wide_String;
703 Last : out Natural)
705 begin
706 Get_Line (Current_In, Item, Last);
707 end Get_Line;
709 function Get_Line (File : File_Type) return Wide_String is
710 Buffer : Wide_String (1 .. 500);
711 Last : Natural;
713 function Get_Rest (S : Wide_String) return Wide_String;
714 -- This is a recursive function that reads the rest of the line and
715 -- returns it. S is the part read so far.
717 --------------
718 -- Get_Rest --
719 --------------
721 function Get_Rest (S : Wide_String) return Wide_String is
723 -- Each time we allocate a buffer the same size as what we have
724 -- read so far. This limits us to a logarithmic number of calls
725 -- to Get_Rest and also ensures only a linear use of stack space.
727 Buffer : Wide_String (1 .. S'Length);
728 Last : Natural;
730 begin
731 Get_Line (File, Buffer, Last);
733 declare
734 R : constant Wide_String := S & Buffer (1 .. Last);
735 begin
736 if Last < Buffer'Last then
737 return R;
738 else
739 return Get_Rest (R);
740 end if;
741 end;
742 end Get_Rest;
744 -- Start of processing for Get_Line
746 begin
747 Get_Line (File, Buffer, Last);
749 if Last < Buffer'Last then
750 return Buffer (1 .. Last);
751 else
752 return Get_Rest (Buffer (1 .. Last));
753 end if;
754 end Get_Line;
756 function Get_Line return Wide_String is
757 begin
758 return Get_Line (Current_In);
759 end Get_Line;
761 -------------------
762 -- Get_Wide_Char --
763 -------------------
765 function Get_Wide_Char
766 (C : Character;
767 File : File_Type) return Wide_Character
769 function In_Char return Character;
770 -- Function used to obtain additional characters it the wide character
771 -- sequence is more than one character long.
773 function WC_In is new Char_Sequence_To_Wide_Char (In_Char);
775 -------------
776 -- In_Char --
777 -------------
779 function In_Char return Character is
780 ch : constant Integer := Getc (File);
781 begin
782 if ch = EOF then
783 raise End_Error;
784 else
785 return Character'Val (ch);
786 end if;
787 end In_Char;
789 -- Start of processing for Get_Wide_Char
791 begin
792 FIO.Check_Read_Status (AP (File));
793 return WC_In (C, File.WC_Method);
794 end Get_Wide_Char;
796 -------------------------
797 -- Get_Wide_Char_Immed --
798 -------------------------
800 function Get_Wide_Char_Immed
801 (C : Character;
802 File : File_Type) return Wide_Character
804 function In_Char return Character;
805 -- Function used to obtain additional characters it the wide character
806 -- sequence is more than one character long.
808 function WC_In is new Char_Sequence_To_Wide_Char (In_Char);
810 -------------
811 -- In_Char --
812 -------------
814 function In_Char return Character is
815 ch : constant Integer := Getc_Immed (File);
816 begin
817 if ch = EOF then
818 raise End_Error;
819 else
820 return Character'Val (ch);
821 end if;
822 end In_Char;
824 -- Start of processing for Get_Wide_Char_Immed
826 begin
827 FIO.Check_Read_Status (AP (File));
828 return WC_In (C, File.WC_Method);
829 end Get_Wide_Char_Immed;
831 ----------
832 -- Getc --
833 ----------
835 function Getc (File : File_Type) return int is
836 ch : int;
838 begin
839 ch := fgetc (File.Stream);
841 if ch = EOF and then ferror (File.Stream) /= 0 then
842 raise Device_Error;
843 else
844 return ch;
845 end if;
846 end Getc;
848 ----------------
849 -- Getc_Immed --
850 ----------------
852 function Getc_Immed (File : File_Type) return int is
853 ch : int;
854 end_of_file : int;
856 procedure getc_immediate
857 (stream : FILEs; ch : out int; end_of_file : out int);
858 pragma Import (C, getc_immediate, "getc_immediate");
860 begin
861 FIO.Check_Read_Status (AP (File));
863 if File.Before_LM then
864 File.Before_LM := False;
865 File.Before_LM_PM := False;
866 ch := LM;
868 else
869 getc_immediate (File.Stream, ch, end_of_file);
871 if ferror (File.Stream) /= 0 then
872 raise Device_Error;
873 elsif end_of_file /= 0 then
874 return EOF;
875 end if;
876 end if;
878 return ch;
879 end Getc_Immed;
881 -------------------------------
882 -- Initialize_Standard_Files --
883 -------------------------------
885 procedure Initialize_Standard_Files is
886 begin
887 Standard_Err.Stream := stderr;
888 Standard_Err.Name := Err_Name'Access;
889 Standard_Err.Form := Null_Str'Unrestricted_Access;
890 Standard_Err.Mode := FCB.Out_File;
891 Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0;
892 Standard_Err.Is_Temporary_File := False;
893 Standard_Err.Is_System_File := True;
894 Standard_Err.Text_Encoding := Default_Text;
895 Standard_Err.Access_Method := 'T';
896 Standard_Err.Self := Standard_Err;
897 Standard_Err.WC_Method := Default_WCEM;
899 Standard_In.Stream := stdin;
900 Standard_In.Name := In_Name'Access;
901 Standard_In.Form := Null_Str'Unrestricted_Access;
902 Standard_In.Mode := FCB.In_File;
903 Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0;
904 Standard_In.Is_Temporary_File := False;
905 Standard_In.Is_System_File := True;
906 Standard_In.Text_Encoding := Default_Text;
907 Standard_In.Access_Method := 'T';
908 Standard_In.Self := Standard_In;
909 Standard_In.WC_Method := Default_WCEM;
911 Standard_Out.Stream := stdout;
912 Standard_Out.Name := Out_Name'Access;
913 Standard_Out.Form := Null_Str'Unrestricted_Access;
914 Standard_Out.Mode := FCB.Out_File;
915 Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0;
916 Standard_Out.Is_Temporary_File := False;
917 Standard_Out.Is_System_File := True;
918 Standard_Out.Text_Encoding := Default_Text;
919 Standard_Out.Access_Method := 'T';
920 Standard_Out.Self := Standard_Out;
921 Standard_Out.WC_Method := Default_WCEM;
923 FIO.Make_Unbuffered (AP (Standard_Out));
924 FIO.Make_Unbuffered (AP (Standard_Err));
925 end Initialize_Standard_Files;
927 -------------
928 -- Is_Open --
929 -------------
931 function Is_Open (File : File_Type) return Boolean is
932 begin
933 return FIO.Is_Open (AP (File));
934 end Is_Open;
936 ----------
937 -- Line --
938 ----------
940 -- Note: we assume that it is impossible in practice for the line to exceed
941 -- the value of Count'Last, i.e. no check is required for overflow raising
942 -- layout error.
944 function Line (File : File_Type) return Positive_Count is
945 begin
946 FIO.Check_File_Open (AP (File));
947 return File.Line;
948 end Line;
950 function Line return Positive_Count is
951 begin
952 return Line (Current_Out);
953 end Line;
955 -----------------
956 -- Line_Length --
957 -----------------
959 function Line_Length (File : File_Type) return Count is
960 begin
961 FIO.Check_Write_Status (AP (File));
962 return File.Line_Length;
963 end Line_Length;
965 function Line_Length return Count is
966 begin
967 return Line_Length (Current_Out);
968 end Line_Length;
970 ----------------
971 -- Look_Ahead --
972 ----------------
974 procedure Look_Ahead
975 (File : File_Type;
976 Item : out Wide_Character;
977 End_Of_Line : out Boolean)
979 ch : int;
981 -- Start of processing for Look_Ahead
983 begin
984 FIO.Check_Read_Status (AP (File));
986 -- If we are logically before a line mark, we can return immediately
988 if File.Before_LM then
989 End_Of_Line := True;
990 Item := Wide_Character'Val (0);
992 -- If we are before a wide character, just return it (this can happen
993 -- if there are two calls to Look_Ahead in a row).
995 elsif File.Before_Wide_Character then
996 End_Of_Line := False;
997 Item := File.Saved_Wide_Character;
999 -- otherwise we must read a character from the input stream
1001 else
1002 ch := Getc (File);
1004 if ch = LM
1005 or else ch = EOF
1006 or else (ch = EOF and then File.Is_Regular_File)
1007 then
1008 End_Of_Line := True;
1009 Ungetc (ch, File);
1010 Item := Wide_Character'Val (0);
1012 -- Case where character obtained does not represent the start of an
1013 -- encoded sequence so it stands for itself and we can unget it with
1014 -- no difficulty.
1016 elsif not Is_Start_Of_Encoding
1017 (Character'Val (ch), File.WC_Method)
1018 then
1019 End_Of_Line := False;
1020 Ungetc (ch, File);
1021 Item := Wide_Character'Val (ch);
1023 -- For the start of an encoding, we read the character using the
1024 -- Get_Wide_Char routine. It will occupy more than one byte so we
1025 -- can't put it back with ungetc. Instead we save it in the control
1026 -- block, setting a flag that everyone interested in reading
1027 -- characters must test before reading the stream.
1029 else
1030 Item := Get_Wide_Char (Character'Val (ch), File);
1031 End_Of_Line := False;
1032 File.Saved_Wide_Character := Item;
1033 File.Before_Wide_Character := True;
1034 end if;
1035 end if;
1036 end Look_Ahead;
1038 procedure Look_Ahead
1039 (Item : out Wide_Character;
1040 End_Of_Line : out Boolean)
1042 begin
1043 Look_Ahead (Current_In, Item, End_Of_Line);
1044 end Look_Ahead;
1046 ----------
1047 -- Mode --
1048 ----------
1050 function Mode (File : File_Type) return File_Mode is
1051 begin
1052 return To_TIO (FIO.Mode (AP (File)));
1053 end Mode;
1055 ----------
1056 -- Name --
1057 ----------
1059 function Name (File : File_Type) return String is
1060 begin
1061 return FIO.Name (AP (File));
1062 end Name;
1064 --------------
1065 -- New_Line --
1066 --------------
1068 procedure New_Line
1069 (File : File_Type;
1070 Spacing : Positive_Count := 1)
1072 begin
1073 -- Raise Constraint_Error if out of range value. The reason for this
1074 -- explicit test is that we don't want junk values around, even if
1075 -- checks are off in the caller.
1077 if not Spacing'Valid then
1078 raise Constraint_Error;
1079 end if;
1081 FIO.Check_Write_Status (AP (File));
1083 for K in 1 .. Spacing loop
1085 -- We use Put here (rather than Putc) so that we get the proper
1086 -- behavior on windows for output of Wide_String to the console.
1088 Put (File, Wide_Character'Val (LM));
1090 File.Line := File.Line + 1;
1092 if File.Page_Length /= 0 and then File.Line > File.Page_Length then
1094 -- Same situation as above, use Put instead of Putc
1096 Put (File, Wide_Character'Val (PM));
1098 File.Line := 1;
1099 File.Page := File.Page + 1;
1100 end if;
1101 end loop;
1103 File.Col := 1;
1104 end New_Line;
1106 procedure New_Line (Spacing : Positive_Count := 1) is
1107 begin
1108 New_Line (Current_Out, Spacing);
1109 end New_Line;
1111 --------------
1112 -- New_Page --
1113 --------------
1115 procedure New_Page (File : File_Type) is
1116 begin
1117 FIO.Check_Write_Status (AP (File));
1119 if File.Col /= 1 or else File.Line = 1 then
1120 Putc (LM, File);
1121 end if;
1123 Putc (PM, File);
1124 File.Page := File.Page + 1;
1125 File.Line := 1;
1126 File.Col := 1;
1127 end New_Page;
1129 procedure New_Page is
1130 begin
1131 New_Page (Current_Out);
1132 end New_Page;
1134 -----------
1135 -- Nextc --
1136 -----------
1138 function Nextc (File : File_Type) return int is
1139 ch : int;
1141 begin
1142 ch := fgetc (File.Stream);
1144 if ch = EOF then
1145 if ferror (File.Stream) /= 0 then
1146 raise Device_Error;
1147 end if;
1149 else
1150 if ungetc (ch, File.Stream) = EOF then
1151 raise Device_Error;
1152 end if;
1153 end if;
1155 return ch;
1156 end Nextc;
1158 ----------
1159 -- Open --
1160 ----------
1162 procedure Open
1163 (File : in out File_Type;
1164 Mode : File_Mode;
1165 Name : String;
1166 Form : String := "")
1168 Dummy_File_Control_Block : Wide_Text_AFCB;
1169 pragma Warnings (Off, Dummy_File_Control_Block);
1170 -- Yes, we know this is never assigned a value, only the tag
1171 -- is used for dispatching purposes, so that's expected.
1173 begin
1174 FIO.Open (File_Ptr => AP (File),
1175 Dummy_FCB => Dummy_File_Control_Block,
1176 Mode => To_FCB (Mode),
1177 Name => Name,
1178 Form => Form,
1179 Amethod => 'W',
1180 Creat => False,
1181 Text => True);
1183 File.Self := File;
1184 Set_WCEM (File);
1185 end Open;
1187 ----------
1188 -- Page --
1189 ----------
1191 -- Note: we assume that it is impossible in practice for the page
1192 -- to exceed the value of Count'Last, i.e. no check is required for
1193 -- overflow raising layout error.
1195 function Page (File : File_Type) return Positive_Count is
1196 begin
1197 FIO.Check_File_Open (AP (File));
1198 return File.Page;
1199 end Page;
1201 function Page return Positive_Count is
1202 begin
1203 return Page (Current_Out);
1204 end Page;
1206 -----------------
1207 -- Page_Length --
1208 -----------------
1210 function Page_Length (File : File_Type) return Count is
1211 begin
1212 FIO.Check_Write_Status (AP (File));
1213 return File.Page_Length;
1214 end Page_Length;
1216 function Page_Length return Count is
1217 begin
1218 return Page_Length (Current_Out);
1219 end Page_Length;
1221 ---------
1222 -- Put --
1223 ---------
1225 procedure Put
1226 (File : File_Type;
1227 Item : Wide_Character)
1229 wide_text_translation_required : Integer;
1230 pragma Import
1231 (C, wide_text_translation_required,
1232 "__gnat_wide_text_translation_required");
1233 -- Text translation is required on Windows only. This means that the
1234 -- console is doing translation and we do not want to do any encoding
1235 -- here. If this variable is not 0 we output the character via fputwc.
1237 procedure Out_Char (C : Character);
1238 -- Procedure to output one character of a wide character sequence
1240 procedure WC_Out is new Wide_Char_To_Char_Sequence (Out_Char);
1242 --------------
1243 -- Out_Char --
1244 --------------
1246 procedure Out_Char (C : Character) is
1247 begin
1248 Putc (Character'Pos (C), File);
1249 end Out_Char;
1251 Discard : int;
1253 -- Start of processing for Put
1255 begin
1256 FIO.Check_Write_Status (AP (File));
1258 if wide_text_translation_required /= 0
1259 or else File.Text_Encoding in Non_Default_Text_Content_Encoding
1260 then
1261 set_mode (fileno (File.Stream), File.Text_Encoding);
1262 Discard := fputwc (Wide_Character'Pos (Item), File.Stream);
1263 else
1264 WC_Out (Item, File.WC_Method);
1265 end if;
1267 File.Col := File.Col + 1;
1268 end Put;
1270 procedure Put (Item : Wide_Character) is
1271 begin
1272 Put (Current_Out, Item);
1273 end Put;
1275 ---------
1276 -- Put --
1277 ---------
1279 procedure Put
1280 (File : File_Type;
1281 Item : Wide_String)
1283 begin
1284 for J in Item'Range loop
1285 Put (File, Item (J));
1286 end loop;
1287 end Put;
1289 procedure Put (Item : Wide_String) is
1290 begin
1291 Put (Current_Out, Item);
1292 end Put;
1294 --------------
1295 -- Put_Line --
1296 --------------
1298 procedure Put_Line
1299 (File : File_Type;
1300 Item : Wide_String)
1302 begin
1303 Put (File, Item);
1304 New_Line (File);
1305 end Put_Line;
1307 procedure Put_Line (Item : Wide_String) is
1308 begin
1309 Put (Current_Out, Item);
1310 New_Line (Current_Out);
1311 end Put_Line;
1313 ----------
1314 -- Putc --
1315 ----------
1317 procedure Putc (ch : int; File : File_Type) is
1318 begin
1319 if fputc (ch, File.Stream) = EOF then
1320 raise Device_Error;
1321 end if;
1322 end Putc;
1324 ----------
1325 -- Read --
1326 ----------
1328 -- This is the primitive Stream Read routine, used when a Text_IO file
1329 -- is treated directly as a stream using Text_IO.Streams.Stream.
1331 procedure Read
1332 (File : in out Wide_Text_AFCB;
1333 Item : out Stream_Element_Array;
1334 Last : out Stream_Element_Offset)
1336 Discard_ch : int;
1337 pragma Unreferenced (Discard_ch);
1339 begin
1340 -- Need to deal with Before_Wide_Character ???
1342 if File.Mode /= FCB.In_File then
1343 raise Mode_Error;
1344 end if;
1346 -- Deal with case where our logical and physical position do not match
1347 -- because of being after an LM or LM-PM sequence when in fact we are
1348 -- logically positioned before it.
1350 if File.Before_LM then
1352 -- If we are before a PM, then it is possible for a stream read
1353 -- to leave us after the LM and before the PM, which is a bit
1354 -- odd. The easiest way to deal with this is to unget the PM,
1355 -- so we are indeed positioned between the characters. This way
1356 -- further stream read operations will work correctly, and the
1357 -- effect on text processing is a little weird, but what can
1358 -- be expected if stream and text input are mixed this way?
1360 if File.Before_LM_PM then
1361 Discard_ch := ungetc (PM, File.Stream);
1362 File.Before_LM_PM := False;
1363 end if;
1365 File.Before_LM := False;
1367 Item (Item'First) := Stream_Element (Character'Pos (ASCII.LF));
1369 if Item'Length = 1 then
1370 Last := Item'Last;
1372 else
1373 Last :=
1374 Item'First +
1375 Stream_Element_Offset
1376 (fread (buffer => Item'Address,
1377 index => size_t (Item'First + 1),
1378 size => 1,
1379 count => Item'Length - 1,
1380 stream => File.Stream));
1381 end if;
1383 return;
1384 end if;
1386 -- Now we do the read. Since this is a text file, it is normally in
1387 -- text mode, but stream data must be read in binary mode, so we
1388 -- temporarily set binary mode for the read, resetting it after.
1389 -- These calls have no effect in a system (like Unix) where there is
1390 -- no distinction between text and binary files.
1392 set_binary_mode (fileno (File.Stream));
1394 Last :=
1395 Item'First +
1396 Stream_Element_Offset
1397 (fread (Item'Address, 1, Item'Length, File.Stream)) - 1;
1399 if Last < Item'Last then
1400 if ferror (File.Stream) /= 0 then
1401 raise Device_Error;
1402 end if;
1403 end if;
1405 set_text_mode (fileno (File.Stream));
1406 end Read;
1408 -----------
1409 -- Reset --
1410 -----------
1412 procedure Reset
1413 (File : in out File_Type;
1414 Mode : File_Mode)
1416 begin
1417 -- Don't allow change of mode for current file (RM A.10.2(5))
1419 if (File = Current_In or else
1420 File = Current_Out or else
1421 File = Current_Error)
1422 and then To_FCB (Mode) /= File.Mode
1423 then
1424 raise Mode_Error;
1425 end if;
1427 Terminate_Line (File);
1428 FIO.Reset (AP (File)'Unrestricted_Access, To_FCB (Mode));
1429 File.Page := 1;
1430 File.Line := 1;
1431 File.Col := 1;
1432 File.Line_Length := 0;
1433 File.Page_Length := 0;
1434 File.Before_LM := False;
1435 File.Before_LM_PM := False;
1436 end Reset;
1438 procedure Reset (File : in out File_Type) is
1439 begin
1440 Terminate_Line (File);
1441 FIO.Reset (AP (File)'Unrestricted_Access);
1442 File.Page := 1;
1443 File.Line := 1;
1444 File.Col := 1;
1445 File.Line_Length := 0;
1446 File.Page_Length := 0;
1447 File.Before_LM := False;
1448 File.Before_LM_PM := False;
1449 end Reset;
1451 -------------
1452 -- Set_Col --
1453 -------------
1455 procedure Set_Col
1456 (File : File_Type;
1457 To : Positive_Count)
1459 ch : int;
1461 begin
1462 -- Raise Constraint_Error if out of range value. The reason for this
1463 -- explicit test is that we don't want junk values around, even if
1464 -- checks are off in the caller.
1466 if not To'Valid then
1467 raise Constraint_Error;
1468 end if;
1470 FIO.Check_File_Open (AP (File));
1472 if To = File.Col then
1473 return;
1474 end if;
1476 if Mode (File) >= Out_File then
1477 if File.Line_Length /= 0 and then To > File.Line_Length then
1478 raise Layout_Error;
1479 end if;
1481 if To < File.Col then
1482 New_Line (File);
1483 end if;
1485 while File.Col < To loop
1486 Put (File, ' ');
1487 end loop;
1489 else
1490 loop
1491 ch := Getc (File);
1493 if ch = EOF then
1494 raise End_Error;
1496 elsif ch = LM then
1497 File.Line := File.Line + 1;
1498 File.Col := 1;
1500 elsif ch = PM and then File.Is_Regular_File then
1501 File.Page := File.Page + 1;
1502 File.Line := 1;
1503 File.Col := 1;
1505 elsif To = File.Col then
1506 Ungetc (ch, File);
1507 return;
1509 else
1510 File.Col := File.Col + 1;
1511 end if;
1512 end loop;
1513 end if;
1514 end Set_Col;
1516 procedure Set_Col (To : Positive_Count) is
1517 begin
1518 Set_Col (Current_Out, To);
1519 end Set_Col;
1521 ---------------
1522 -- Set_Error --
1523 ---------------
1525 procedure Set_Error (File : File_Type) is
1526 begin
1527 FIO.Check_Write_Status (AP (File));
1528 Current_Err := File;
1529 end Set_Error;
1531 ---------------
1532 -- Set_Input --
1533 ---------------
1535 procedure Set_Input (File : File_Type) is
1536 begin
1537 FIO.Check_Read_Status (AP (File));
1538 Current_In := File;
1539 end Set_Input;
1541 --------------
1542 -- Set_Line --
1543 --------------
1545 procedure Set_Line
1546 (File : File_Type;
1547 To : Positive_Count)
1549 begin
1550 -- Raise Constraint_Error if out of range value. The reason for this
1551 -- explicit test is that we don't want junk values around, even if
1552 -- checks are off in the caller.
1554 if not To'Valid then
1555 raise Constraint_Error;
1556 end if;
1558 FIO.Check_File_Open (AP (File));
1560 if To = File.Line then
1561 return;
1562 end if;
1564 if Mode (File) >= Out_File then
1565 if File.Page_Length /= 0 and then To > File.Page_Length then
1566 raise Layout_Error;
1567 end if;
1569 if To < File.Line then
1570 New_Page (File);
1571 end if;
1573 while File.Line < To loop
1574 New_Line (File);
1575 end loop;
1577 else
1578 while To /= File.Line loop
1579 Skip_Line (File);
1580 end loop;
1581 end if;
1582 end Set_Line;
1584 procedure Set_Line (To : Positive_Count) is
1585 begin
1586 Set_Line (Current_Out, To);
1587 end Set_Line;
1589 ---------------------
1590 -- Set_Line_Length --
1591 ---------------------
1593 procedure Set_Line_Length (File : File_Type; To : Count) is
1594 begin
1595 -- Raise Constraint_Error if out of range value. The reason for this
1596 -- explicit test is that we don't want junk values around, even if
1597 -- checks are off in the caller.
1599 if not To'Valid then
1600 raise Constraint_Error;
1601 end if;
1603 FIO.Check_Write_Status (AP (File));
1604 File.Line_Length := To;
1605 end Set_Line_Length;
1607 procedure Set_Line_Length (To : Count) is
1608 begin
1609 Set_Line_Length (Current_Out, To);
1610 end Set_Line_Length;
1612 ----------------
1613 -- Set_Output --
1614 ----------------
1616 procedure Set_Output (File : File_Type) is
1617 begin
1618 FIO.Check_Write_Status (AP (File));
1619 Current_Out := File;
1620 end Set_Output;
1622 ---------------------
1623 -- Set_Page_Length --
1624 ---------------------
1626 procedure Set_Page_Length (File : File_Type; To : Count) is
1627 begin
1628 -- Raise Constraint_Error if out of range value. The reason for this
1629 -- explicit test is that we don't want junk values around, even if
1630 -- checks are off in the caller.
1632 if not To'Valid then
1633 raise Constraint_Error;
1634 end if;
1636 FIO.Check_Write_Status (AP (File));
1637 File.Page_Length := To;
1638 end Set_Page_Length;
1640 procedure Set_Page_Length (To : Count) is
1641 begin
1642 Set_Page_Length (Current_Out, To);
1643 end Set_Page_Length;
1645 --------------
1646 -- Set_WCEM --
1647 --------------
1649 procedure Set_WCEM (File : in out File_Type) is
1650 Start : Natural;
1651 Stop : Natural;
1653 begin
1654 FIO.Form_Parameter (File.Form.all, "wcem", Start, Stop);
1656 if Start = 0 then
1657 File.WC_Method := Default_WCEM;
1659 else
1660 if Stop = Start then
1661 for J in WC_Encoding_Letters'Range loop
1662 if File.Form (Start) = WC_Encoding_Letters (J) then
1663 File.WC_Method := J;
1664 return;
1665 end if;
1666 end loop;
1667 end if;
1669 Close (File);
1670 raise Use_Error with "invalid WCEM form parameter";
1671 end if;
1672 end Set_WCEM;
1674 ---------------
1675 -- Skip_Line --
1676 ---------------
1678 procedure Skip_Line
1679 (File : File_Type;
1680 Spacing : Positive_Count := 1)
1682 ch : int;
1684 begin
1685 -- Raise Constraint_Error if out of range value. The reason for this
1686 -- explicit test is that we don't want junk values around, even if
1687 -- checks are off in the caller.
1689 if not Spacing'Valid then
1690 raise Constraint_Error;
1691 end if;
1693 FIO.Check_Read_Status (AP (File));
1695 for L in 1 .. Spacing loop
1696 if File.Before_LM then
1697 File.Before_LM := False;
1698 File.Before_LM_PM := False;
1700 else
1701 ch := Getc (File);
1703 -- If at end of file now, then immediately raise End_Error. Note
1704 -- that we can never be positioned between a line mark and a page
1705 -- mark, so if we are at the end of file, we cannot logically be
1706 -- before the implicit page mark that is at the end of the file.
1708 -- For the same reason, we do not need an explicit check for a
1709 -- page mark. If there is a FF in the middle of a line, the file
1710 -- is not in canonical format and we do not care about the page
1711 -- numbers for files other than ones in canonical format.
1713 if ch = EOF then
1714 raise End_Error;
1715 end if;
1717 -- If not at end of file, then loop till we get to an LM or EOF.
1718 -- The latter case happens only in non-canonical files where the
1719 -- last line is not terminated by LM, but we don't want to blow
1720 -- up for such files, so we assume an implicit LM in this case.
1722 loop
1723 exit when ch = LM or else ch = EOF;
1724 ch := Getc (File);
1725 end loop;
1726 end if;
1728 -- We have got past a line mark, now, for a regular file only,
1729 -- see if a page mark immediately follows this line mark and
1730 -- if so, skip past the page mark as well. We do not do this
1731 -- for non-regular files, since it would cause an undesirable
1732 -- wait for an additional character.
1734 File.Col := 1;
1735 File.Line := File.Line + 1;
1737 if File.Before_LM_PM then
1738 File.Page := File.Page + 1;
1739 File.Line := 1;
1740 File.Before_LM_PM := False;
1742 elsif File.Is_Regular_File then
1743 ch := Getc (File);
1745 -- Page mark can be explicit, or implied at the end of the file
1747 if (ch = PM or else ch = EOF)
1748 and then File.Is_Regular_File
1749 then
1750 File.Page := File.Page + 1;
1751 File.Line := 1;
1752 else
1753 Ungetc (ch, File);
1754 end if;
1755 end if;
1756 end loop;
1758 File.Before_Wide_Character := False;
1759 end Skip_Line;
1761 procedure Skip_Line (Spacing : Positive_Count := 1) is
1762 begin
1763 Skip_Line (Current_In, Spacing);
1764 end Skip_Line;
1766 ---------------
1767 -- Skip_Page --
1768 ---------------
1770 procedure Skip_Page (File : File_Type) is
1771 ch : int;
1773 begin
1774 FIO.Check_Read_Status (AP (File));
1776 -- If at page mark already, just skip it
1778 if File.Before_LM_PM then
1779 File.Before_LM := False;
1780 File.Before_LM_PM := False;
1781 File.Page := File.Page + 1;
1782 File.Line := 1;
1783 File.Col := 1;
1784 return;
1785 end if;
1787 -- This is a bit tricky, if we are logically before an LM then
1788 -- it is not an error if we are at an end of file now, since we
1789 -- are not really at it.
1791 if File.Before_LM then
1792 File.Before_LM := False;
1793 File.Before_LM_PM := False;
1794 ch := Getc (File);
1796 -- Otherwise we do raise End_Error if we are at the end of file now
1798 else
1799 ch := Getc (File);
1801 if ch = EOF then
1802 raise End_Error;
1803 end if;
1804 end if;
1806 -- Now we can just rumble along to the next page mark, or to the
1807 -- end of file, if that comes first. The latter case happens when
1808 -- the page mark is implied at the end of file.
1810 loop
1811 exit when ch = EOF
1812 or else (ch = PM and then File.Is_Regular_File);
1813 ch := Getc (File);
1814 end loop;
1816 File.Page := File.Page + 1;
1817 File.Line := 1;
1818 File.Col := 1;
1819 File.Before_Wide_Character := False;
1820 end Skip_Page;
1822 procedure Skip_Page is
1823 begin
1824 Skip_Page (Current_In);
1825 end Skip_Page;
1827 --------------------
1828 -- Standard_Error --
1829 --------------------
1831 function Standard_Error return File_Type is
1832 begin
1833 return Standard_Err;
1834 end Standard_Error;
1836 function Standard_Error return File_Access is
1837 begin
1838 return Standard_Err'Access;
1839 end Standard_Error;
1841 --------------------
1842 -- Standard_Input --
1843 --------------------
1845 function Standard_Input return File_Type is
1846 begin
1847 return Standard_In;
1848 end Standard_Input;
1850 function Standard_Input return File_Access is
1851 begin
1852 return Standard_In'Access;
1853 end Standard_Input;
1855 ---------------------
1856 -- Standard_Output --
1857 ---------------------
1859 function Standard_Output return File_Type is
1860 begin
1861 return Standard_Out;
1862 end Standard_Output;
1864 function Standard_Output return File_Access is
1865 begin
1866 return Standard_Out'Access;
1867 end Standard_Output;
1869 --------------------
1870 -- Terminate_Line --
1871 --------------------
1873 procedure Terminate_Line (File : File_Type) is
1874 begin
1875 FIO.Check_File_Open (AP (File));
1877 -- For file other than In_File, test for needing to terminate last line
1879 if Mode (File) /= In_File then
1881 -- If not at start of line definition need new line
1883 if File.Col /= 1 then
1884 New_Line (File);
1886 -- For files other than standard error and standard output, we
1887 -- make sure that an empty file has a single line feed, so that
1888 -- it is properly formatted. We avoid this for the standard files
1889 -- because it is too much of a nuisance to have these odd line
1890 -- feeds when nothing has been written to the file.
1892 elsif (File /= Standard_Err and then File /= Standard_Out)
1893 and then (File.Line = 1 and then File.Page = 1)
1894 then
1895 New_Line (File);
1896 end if;
1897 end if;
1898 end Terminate_Line;
1900 ------------
1901 -- Ungetc --
1902 ------------
1904 procedure Ungetc (ch : int; File : File_Type) is
1905 begin
1906 if ch /= EOF then
1907 if ungetc (ch, File.Stream) = EOF then
1908 raise Device_Error;
1909 end if;
1910 end if;
1911 end Ungetc;
1913 -----------
1914 -- Write --
1915 -----------
1917 -- This is the primitive Stream Write routine, used when a Text_IO file
1918 -- is treated directly as a stream using Text_IO.Streams.Stream.
1920 procedure Write
1921 (File : in out Wide_Text_AFCB;
1922 Item : Stream_Element_Array)
1924 pragma Warnings (Off, File);
1925 -- Because in this implementation we don't need IN OUT, we only read
1927 Siz : constant size_t := Item'Length;
1929 begin
1930 if File.Mode = FCB.In_File then
1931 raise Mode_Error;
1932 end if;
1934 -- Now we do the write. Since this is a text file, it is normally in
1935 -- text mode, but stream data must be written in binary mode, so we
1936 -- temporarily set binary mode for the write, resetting it after.
1937 -- These calls have no effect in a system (like Unix) where there is
1938 -- no distinction between text and binary files.
1940 set_binary_mode (fileno (File.Stream));
1942 if fwrite (Item'Address, 1, Siz, File.Stream) /= Siz then
1943 raise Device_Error;
1944 end if;
1946 set_text_mode (fileno (File.Stream));
1947 end Write;
1949 begin
1950 -- Initialize Standard Files
1952 for J in WC_Encoding_Method loop
1953 if WC_Encoding = WC_Encoding_Letters (J) then
1954 Default_WCEM := J;
1955 end if;
1956 end loop;
1958 Initialize_Standard_Files;
1960 FIO.Chain_File (AP (Standard_In));
1961 FIO.Chain_File (AP (Standard_Out));
1962 FIO.Chain_File (AP (Standard_Err));
1964 end Ada.Wide_Text_IO;