cfgexpand: Expand comment on when non-var clobbers can show up
[official-gcc.git] / gcc / ada / libgnat / a-ztexio.adb
blobc22d52272e355ff9272d1a5315913a59c2d36fd0
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- A D A . W I D E _ 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_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_Wide_Char_Immed
85 (C : Character;
86 File : File_Type) return Wide_Wide_Character;
87 -- This routine is identical to Get_Wide_Wide_Char, except that the reads
88 -- are 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_Wide_Text_AFCB) return FCB.AFCB_Ptr
123 pragma Unreferenced (Control_Block);
124 begin
125 return new Wide_Wide_Text_AFCB;
126 end AFCB_Allocate;
128 ----------------
129 -- AFCB_Close --
130 ----------------
132 procedure AFCB_Close (File : not null access Wide_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_Wide_Text_AFCB) is
155 FT : File_Type := File.all'Access;
157 procedure Free is new
158 Ada.Unchecked_Deallocation (Wide_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_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_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_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_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_Wide_Character)
447 C : Character;
449 begin
450 FIO.Check_Read_Status (AP (File));
452 if File.Before_Wide_Wide_Character then
453 File.Before_Wide_Wide_Character := False;
454 Item := File.Saved_Wide_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_Wide_Char (C, File);
461 end if;
462 end Get;
464 procedure Get (Item : out Wide_Wide_Character) is
465 begin
466 Get (Current_In, Item);
467 end Get;
469 procedure Get
470 (File : File_Type;
471 Item : out Wide_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_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_Wide_Character)
540 ch : int;
542 begin
543 FIO.Check_Read_Status (AP (File));
545 if File.Before_Wide_Wide_Character then
546 File.Before_Wide_Wide_Character := False;
547 Item := File.Saved_Wide_Wide_Character;
549 elsif File.Before_LM then
550 File.Before_LM := False;
551 File.Before_LM_PM := False;
552 Item := Wide_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_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_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_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_Wide_Character then
584 File.Before_Wide_Wide_Character := False;
585 Item := File.Saved_Wide_Wide_Character;
587 elsif File.Before_LM then
588 File.Before_LM := False;
589 File.Before_LM_PM := False;
590 Item := Wide_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_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_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_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,
666 -- but this is not an official page mark in any case, since
667 -- official page marks can only follow a line mark. The whole
668 -- page business is pretty much nonsense anyway, so we do not
669 -- want to waste time trying to make sense out of non-standard
670 -- page marks in the file. This means that the behavior of
671 -- Get_Line is different from repeated Get of a character, but
672 -- that's too bad. We only promise that page numbers etc make
673 -- sense if the file 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_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_Wide_String is
710 Buffer : Wide_Wide_String (1 .. 500);
711 Last : Natural;
713 function Get_Rest (S : Wide_Wide_String) return Wide_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_Wide_String) return Wide_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_Wide_String (1 .. S'Length);
728 Last : Natural;
730 begin
731 Get_Line (File, Buffer, Last);
733 declare
734 R : constant Wide_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_Wide_String is
757 begin
758 return Get_Line (Current_In);
759 end Get_Line;
761 ------------------------
762 -- Get_Wide_Wide_Char --
763 ------------------------
765 function Get_Wide_Wide_Char
766 (C : Character;
767 File : File_Type) return Wide_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_UTF_32 (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_Wide_Char
791 begin
792 FIO.Check_Read_Status (AP (File));
793 return Wide_Wide_Character'Val (WC_In (C, File.WC_Method));
794 end Get_Wide_Wide_Char;
796 ------------------------------
797 -- Get_Wide_Wide_Char_Immed --
798 ------------------------------
800 function Get_Wide_Wide_Char_Immed
801 (C : Character;
802 File : File_Type) return Wide_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_UTF_32 (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_Wide_Char_Immed
826 begin
827 FIO.Check_Read_Status (AP (File));
828 return Wide_Wide_Character'Val (WC_In (C, File.WC_Method));
829 end Get_Wide_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
941 -- to exceed the value of Count'Last, i.e. no check is required for
942 -- overflow raising 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_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_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_Wide_Character then
996 End_Of_Line := False;
997 Item := File.Saved_Wide_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_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_Wide_Character'Val (ch);
1023 -- For the start of an encoding, we read the character using the
1024 -- Get_Wide_Wide_Char routine. It will occupy more than one byte so
1025 -- we can't put it back with ungetc. Instead we save it in the
1026 -- control block, setting a flag that everyone interested in reading
1027 -- characters must test before reading the stream.
1029 else
1030 Item := Get_Wide_Wide_Char (Character'Val (ch), File);
1031 End_Of_Line := False;
1032 File.Saved_Wide_Wide_Character := Item;
1033 File.Before_Wide_Wide_Character := True;
1034 end if;
1035 end if;
1036 end Look_Ahead;
1038 procedure Look_Ahead
1039 (Item : out Wide_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
1084 Putc (LM, File);
1085 File.Line := File.Line + 1;
1087 if File.Page_Length /= 0
1088 and then File.Line > File.Page_Length
1089 then
1090 Putc (PM, File);
1091 File.Line := 1;
1092 File.Page := File.Page + 1;
1093 end if;
1094 end loop;
1096 File.Col := 1;
1097 end New_Line;
1099 procedure New_Line (Spacing : Positive_Count := 1) is
1100 begin
1101 New_Line (Current_Out, Spacing);
1102 end New_Line;
1104 --------------
1105 -- New_Page --
1106 --------------
1108 procedure New_Page (File : File_Type) is
1109 begin
1110 FIO.Check_Write_Status (AP (File));
1112 if File.Col /= 1 or else File.Line = 1 then
1113 Putc (LM, File);
1114 end if;
1116 Putc (PM, File);
1117 File.Page := File.Page + 1;
1118 File.Line := 1;
1119 File.Col := 1;
1120 end New_Page;
1122 procedure New_Page is
1123 begin
1124 New_Page (Current_Out);
1125 end New_Page;
1127 -----------
1128 -- Nextc --
1129 -----------
1131 function Nextc (File : File_Type) return int is
1132 ch : int;
1134 begin
1135 ch := fgetc (File.Stream);
1137 if ch = EOF then
1138 if ferror (File.Stream) /= 0 then
1139 raise Device_Error;
1140 end if;
1142 else
1143 if ungetc (ch, File.Stream) = EOF then
1144 raise Device_Error;
1145 end if;
1146 end if;
1148 return ch;
1149 end Nextc;
1151 ----------
1152 -- Open --
1153 ----------
1155 procedure Open
1156 (File : in out File_Type;
1157 Mode : File_Mode;
1158 Name : String;
1159 Form : String := "")
1161 Dummy_File_Control_Block : Wide_Wide_Text_AFCB;
1162 pragma Warnings (Off, Dummy_File_Control_Block);
1163 -- Yes, we know this is never assigned a value, only the tag
1164 -- is used for dispatching purposes, so that's expected.
1166 begin
1167 FIO.Open (File_Ptr => AP (File),
1168 Dummy_FCB => Dummy_File_Control_Block,
1169 Mode => To_FCB (Mode),
1170 Name => Name,
1171 Form => Form,
1172 Amethod => 'W',
1173 Creat => False,
1174 Text => True);
1176 File.Self := File;
1177 Set_WCEM (File);
1178 end Open;
1180 ----------
1181 -- Page --
1182 ----------
1184 -- Note: we assume that it is impossible in practice for the page
1185 -- to exceed the value of Count'Last, i.e. no check is required for
1186 -- overflow raising layout error.
1188 function Page (File : File_Type) return Positive_Count is
1189 begin
1190 FIO.Check_File_Open (AP (File));
1191 return File.Page;
1192 end Page;
1194 function Page return Positive_Count is
1195 begin
1196 return Page (Current_Out);
1197 end Page;
1199 -----------------
1200 -- Page_Length --
1201 -----------------
1203 function Page_Length (File : File_Type) return Count is
1204 begin
1205 FIO.Check_Write_Status (AP (File));
1206 return File.Page_Length;
1207 end Page_Length;
1209 function Page_Length return Count is
1210 begin
1211 return Page_Length (Current_Out);
1212 end Page_Length;
1214 ---------
1215 -- Put --
1216 ---------
1218 procedure Put
1219 (File : File_Type;
1220 Item : Wide_Wide_Character)
1222 procedure Out_Char (C : Character);
1223 -- Procedure to output one character of a wide character sequence
1225 procedure WC_Out is new UTF_32_To_Char_Sequence (Out_Char);
1227 --------------
1228 -- Out_Char --
1229 --------------
1231 procedure Out_Char (C : Character) is
1232 begin
1233 Putc (Character'Pos (C), File);
1234 end Out_Char;
1236 -- Start of processing for Put
1238 begin
1239 FIO.Check_Write_Status (AP (File));
1240 WC_Out (Wide_Wide_Character'Pos (Item), File.WC_Method);
1241 File.Col := File.Col + 1;
1242 end Put;
1244 procedure Put (Item : Wide_Wide_Character) is
1245 begin
1246 Put (Current_Out, Item);
1247 end Put;
1249 ---------
1250 -- Put --
1251 ---------
1253 procedure Put
1254 (File : File_Type;
1255 Item : Wide_Wide_String)
1257 begin
1258 for J in Item'Range loop
1259 Put (File, Item (J));
1260 end loop;
1261 end Put;
1263 procedure Put (Item : Wide_Wide_String) is
1264 begin
1265 Put (Current_Out, Item);
1266 end Put;
1268 --------------
1269 -- Put_Line --
1270 --------------
1272 procedure Put_Line
1273 (File : File_Type;
1274 Item : Wide_Wide_String)
1276 begin
1277 Put (File, Item);
1278 New_Line (File);
1279 end Put_Line;
1281 procedure Put_Line (Item : Wide_Wide_String) is
1282 begin
1283 Put (Current_Out, Item);
1284 New_Line (Current_Out);
1285 end Put_Line;
1287 ----------
1288 -- Putc --
1289 ----------
1291 procedure Putc (ch : int; File : File_Type) is
1292 begin
1293 if fputc (ch, File.Stream) = EOF then
1294 raise Device_Error;
1295 end if;
1296 end Putc;
1298 ----------
1299 -- Read --
1300 ----------
1302 -- This is the primitive Stream Read routine, used when a Text_IO file
1303 -- is treated directly as a stream using Text_IO.Streams.Stream.
1305 procedure Read
1306 (File : in out Wide_Wide_Text_AFCB;
1307 Item : out Stream_Element_Array;
1308 Last : out Stream_Element_Offset)
1310 Discard_ch : int;
1311 pragma Unreferenced (Discard_ch);
1313 begin
1314 -- Need to deal with Before_Wide_Wide_Character ???
1316 if File.Mode /= FCB.In_File then
1317 raise Mode_Error;
1318 end if;
1320 -- Deal with case where our logical and physical position do not match
1321 -- because of being after an LM or LM-PM sequence when in fact we are
1322 -- logically positioned before it.
1324 if File.Before_LM then
1326 -- If we are before a PM, then it is possible for a stream read
1327 -- to leave us after the LM and before the PM, which is a bit
1328 -- odd. The easiest way to deal with this is to unget the PM,
1329 -- so we are indeed positioned between the characters. This way
1330 -- further stream read operations will work correctly, and the
1331 -- effect on text processing is a little weird, but what can
1332 -- be expected if stream and text input are mixed this way?
1334 if File.Before_LM_PM then
1335 Discard_ch := ungetc (PM, File.Stream);
1336 File.Before_LM_PM := False;
1337 end if;
1339 File.Before_LM := False;
1341 Item (Item'First) := Stream_Element (Character'Pos (ASCII.LF));
1343 if Item'Length = 1 then
1344 Last := Item'Last;
1346 else
1347 Last :=
1348 Item'First +
1349 Stream_Element_Offset
1350 (fread (buffer => Item'Address,
1351 index => size_t (Item'First + 1),
1352 size => 1,
1353 count => Item'Length - 1,
1354 stream => File.Stream));
1355 end if;
1357 return;
1358 end if;
1360 -- Now we do the read. Since this is a text file, it is normally in
1361 -- text mode, but stream data must be read in binary mode, so we
1362 -- temporarily set binary mode for the read, resetting it after.
1363 -- These calls have no effect in a system (like Unix) where there is
1364 -- no distinction between text and binary files.
1366 set_binary_mode (fileno (File.Stream));
1368 Last :=
1369 Item'First +
1370 Stream_Element_Offset
1371 (fread (Item'Address, 1, Item'Length, File.Stream)) - 1;
1373 if Last < Item'Last then
1374 if ferror (File.Stream) /= 0 then
1375 raise Device_Error;
1376 end if;
1377 end if;
1379 set_text_mode (fileno (File.Stream));
1380 end Read;
1382 -----------
1383 -- Reset --
1384 -----------
1386 procedure Reset
1387 (File : in out File_Type;
1388 Mode : File_Mode)
1390 begin
1391 -- Don't allow change of mode for current file (RM A.10.2(5))
1393 if (File = Current_In or else
1394 File = Current_Out or else
1395 File = Current_Error)
1396 and then To_FCB (Mode) /= File.Mode
1397 then
1398 raise Mode_Error;
1399 end if;
1401 Terminate_Line (File);
1402 FIO.Reset (AP (File)'Unrestricted_Access, To_FCB (Mode));
1403 File.Page := 1;
1404 File.Line := 1;
1405 File.Col := 1;
1406 File.Line_Length := 0;
1407 File.Page_Length := 0;
1408 File.Before_LM := False;
1409 File.Before_LM_PM := False;
1410 end Reset;
1412 procedure Reset (File : in out File_Type) is
1413 begin
1414 Terminate_Line (File);
1415 FIO.Reset (AP (File)'Unrestricted_Access);
1416 File.Page := 1;
1417 File.Line := 1;
1418 File.Col := 1;
1419 File.Line_Length := 0;
1420 File.Page_Length := 0;
1421 File.Before_LM := False;
1422 File.Before_LM_PM := False;
1423 end Reset;
1425 -------------
1426 -- Set_Col --
1427 -------------
1429 procedure Set_Col
1430 (File : File_Type;
1431 To : Positive_Count)
1433 ch : int;
1435 begin
1436 -- Raise Constraint_Error if out of range value. The reason for this
1437 -- explicit test is that we don't want junk values around, even if
1438 -- checks are off in the caller.
1440 if not To'Valid then
1441 raise Constraint_Error;
1442 end if;
1444 FIO.Check_File_Open (AP (File));
1446 if To = File.Col then
1447 return;
1448 end if;
1450 if Mode (File) >= Out_File then
1451 if File.Line_Length /= 0 and then To > File.Line_Length then
1452 raise Layout_Error;
1453 end if;
1455 if To < File.Col then
1456 New_Line (File);
1457 end if;
1459 while File.Col < To loop
1460 Put (File, ' ');
1461 end loop;
1463 else
1464 loop
1465 ch := Getc (File);
1467 if ch = EOF then
1468 raise End_Error;
1470 elsif ch = LM then
1471 File.Line := File.Line + 1;
1472 File.Col := 1;
1474 elsif ch = PM and then File.Is_Regular_File then
1475 File.Page := File.Page + 1;
1476 File.Line := 1;
1477 File.Col := 1;
1479 elsif To = File.Col then
1480 Ungetc (ch, File);
1481 return;
1483 else
1484 File.Col := File.Col + 1;
1485 end if;
1486 end loop;
1487 end if;
1488 end Set_Col;
1490 procedure Set_Col (To : Positive_Count) is
1491 begin
1492 Set_Col (Current_Out, To);
1493 end Set_Col;
1495 ---------------
1496 -- Set_Error --
1497 ---------------
1499 procedure Set_Error (File : File_Type) is
1500 begin
1501 FIO.Check_Write_Status (AP (File));
1502 Current_Err := File;
1503 end Set_Error;
1505 ---------------
1506 -- Set_Input --
1507 ---------------
1509 procedure Set_Input (File : File_Type) is
1510 begin
1511 FIO.Check_Read_Status (AP (File));
1512 Current_In := File;
1513 end Set_Input;
1515 --------------
1516 -- Set_Line --
1517 --------------
1519 procedure Set_Line
1520 (File : File_Type;
1521 To : Positive_Count)
1523 begin
1524 -- Raise Constraint_Error if out of range value. The reason for this
1525 -- explicit test is that we don't want junk values around, even if
1526 -- checks are off in the caller.
1528 if not To'Valid then
1529 raise Constraint_Error;
1530 end if;
1532 FIO.Check_File_Open (AP (File));
1534 if To = File.Line then
1535 return;
1536 end if;
1538 if Mode (File) >= Out_File then
1539 if File.Page_Length /= 0 and then To > File.Page_Length then
1540 raise Layout_Error;
1541 end if;
1543 if To < File.Line then
1544 New_Page (File);
1545 end if;
1547 while File.Line < To loop
1548 New_Line (File);
1549 end loop;
1551 else
1552 while To /= File.Line loop
1553 Skip_Line (File);
1554 end loop;
1555 end if;
1556 end Set_Line;
1558 procedure Set_Line (To : Positive_Count) is
1559 begin
1560 Set_Line (Current_Out, To);
1561 end Set_Line;
1563 ---------------------
1564 -- Set_Line_Length --
1565 ---------------------
1567 procedure Set_Line_Length (File : File_Type; To : Count) is
1568 begin
1569 -- Raise Constraint_Error if out of range value. The reason for this
1570 -- explicit test is that we don't want junk values around, even if
1571 -- checks are off in the caller.
1573 if not To'Valid then
1574 raise Constraint_Error;
1575 end if;
1577 FIO.Check_Write_Status (AP (File));
1578 File.Line_Length := To;
1579 end Set_Line_Length;
1581 procedure Set_Line_Length (To : Count) is
1582 begin
1583 Set_Line_Length (Current_Out, To);
1584 end Set_Line_Length;
1586 ----------------
1587 -- Set_Output --
1588 ----------------
1590 procedure Set_Output (File : File_Type) is
1591 begin
1592 FIO.Check_Write_Status (AP (File));
1593 Current_Out := File;
1594 end Set_Output;
1596 ---------------------
1597 -- Set_Page_Length --
1598 ---------------------
1600 procedure Set_Page_Length (File : File_Type; To : Count) is
1601 begin
1602 -- Raise Constraint_Error if out of range value. The reason for this
1603 -- explicit test is that we don't want junk values around, even if
1604 -- checks are off in the caller.
1606 if not To'Valid then
1607 raise Constraint_Error;
1608 end if;
1610 FIO.Check_Write_Status (AP (File));
1611 File.Page_Length := To;
1612 end Set_Page_Length;
1614 procedure Set_Page_Length (To : Count) is
1615 begin
1616 Set_Page_Length (Current_Out, To);
1617 end Set_Page_Length;
1619 --------------
1620 -- Set_WCEM --
1621 --------------
1623 procedure Set_WCEM (File : in out File_Type) is
1624 Start : Natural;
1625 Stop : Natural;
1627 begin
1628 FIO.Form_Parameter (File.Form.all, "wcem", Start, Stop);
1630 if Start = 0 then
1631 File.WC_Method := Default_WCEM;
1633 else
1634 if Stop = Start then
1635 for J in WC_Encoding_Letters'Range loop
1636 if File.Form (Start) = WC_Encoding_Letters (J) then
1637 File.WC_Method := J;
1638 return;
1639 end if;
1640 end loop;
1641 end if;
1643 Close (File);
1644 raise Use_Error with "invalid WCEM form parameter";
1645 end if;
1646 end Set_WCEM;
1648 ---------------
1649 -- Skip_Line --
1650 ---------------
1652 procedure Skip_Line
1653 (File : File_Type;
1654 Spacing : Positive_Count := 1)
1656 ch : int;
1658 begin
1659 -- Raise Constraint_Error if out of range value. The reason for this
1660 -- explicit test is that we don't want junk values around, even if
1661 -- checks are off in the caller.
1663 if not Spacing'Valid then
1664 raise Constraint_Error;
1665 end if;
1667 FIO.Check_Read_Status (AP (File));
1669 for L in 1 .. Spacing loop
1670 if File.Before_LM then
1671 File.Before_LM := False;
1672 File.Before_LM_PM := False;
1674 else
1675 ch := Getc (File);
1677 -- If at end of file now, then immediately raise End_Error. Note
1678 -- that we can never be positioned between a line mark and a page
1679 -- mark, so if we are at the end of file, we cannot logically be
1680 -- before the implicit page mark that is at the end of the file.
1682 -- For the same reason, we do not need an explicit check for a
1683 -- page mark. If there is a FF in the middle of a line, the file
1684 -- is not in canonical format and we do not care about the page
1685 -- numbers for files other than ones in canonical format.
1687 if ch = EOF then
1688 raise End_Error;
1689 end if;
1691 -- If not at end of file, then loop till we get to an LM or EOF.
1692 -- The latter case happens only in non-canonical files where the
1693 -- last line is not terminated by LM, but we don't want to blow
1694 -- up for such files, so we assume an implicit LM in this case.
1696 loop
1697 exit when ch = LM or else ch = EOF;
1698 ch := Getc (File);
1699 end loop;
1700 end if;
1702 -- We have got past a line mark, now, for a regular file only,
1703 -- see if a page mark immediately follows this line mark and
1704 -- if so, skip past the page mark as well. We do not do this
1705 -- for non-regular files, since it would cause an undesirable
1706 -- wait for an additional character.
1708 File.Col := 1;
1709 File.Line := File.Line + 1;
1711 if File.Before_LM_PM then
1712 File.Page := File.Page + 1;
1713 File.Line := 1;
1714 File.Before_LM_PM := False;
1716 elsif File.Is_Regular_File then
1717 ch := Getc (File);
1719 -- Page mark can be explicit, or implied at the end of the file
1721 if (ch = PM or else ch = EOF)
1722 and then File.Is_Regular_File
1723 then
1724 File.Page := File.Page + 1;
1725 File.Line := 1;
1726 else
1727 Ungetc (ch, File);
1728 end if;
1729 end if;
1730 end loop;
1732 File.Before_Wide_Wide_Character := False;
1733 end Skip_Line;
1735 procedure Skip_Line (Spacing : Positive_Count := 1) is
1736 begin
1737 Skip_Line (Current_In, Spacing);
1738 end Skip_Line;
1740 ---------------
1741 -- Skip_Page --
1742 ---------------
1744 procedure Skip_Page (File : File_Type) is
1745 ch : int;
1747 begin
1748 FIO.Check_Read_Status (AP (File));
1750 -- If at page mark already, just skip it
1752 if File.Before_LM_PM then
1753 File.Before_LM := False;
1754 File.Before_LM_PM := False;
1755 File.Page := File.Page + 1;
1756 File.Line := 1;
1757 File.Col := 1;
1758 return;
1759 end if;
1761 -- This is a bit tricky, if we are logically before an LM then
1762 -- it is not an error if we are at an end of file now, since we
1763 -- are not really at it.
1765 if File.Before_LM then
1766 File.Before_LM := False;
1767 File.Before_LM_PM := False;
1768 ch := Getc (File);
1770 -- Otherwise we do raise End_Error if we are at the end of file now
1772 else
1773 ch := Getc (File);
1775 if ch = EOF then
1776 raise End_Error;
1777 end if;
1778 end if;
1780 -- Now we can just rumble along to the next page mark, or to the
1781 -- end of file, if that comes first. The latter case happens when
1782 -- the page mark is implied at the end of file.
1784 loop
1785 exit when ch = EOF
1786 or else (ch = PM and then File.Is_Regular_File);
1787 ch := Getc (File);
1788 end loop;
1790 File.Page := File.Page + 1;
1791 File.Line := 1;
1792 File.Col := 1;
1793 File.Before_Wide_Wide_Character := False;
1794 end Skip_Page;
1796 procedure Skip_Page is
1797 begin
1798 Skip_Page (Current_In);
1799 end Skip_Page;
1801 --------------------
1802 -- Standard_Error --
1803 --------------------
1805 function Standard_Error return File_Type is
1806 begin
1807 return Standard_Err;
1808 end Standard_Error;
1810 function Standard_Error return File_Access is
1811 begin
1812 return Standard_Err'Access;
1813 end Standard_Error;
1815 --------------------
1816 -- Standard_Input --
1817 --------------------
1819 function Standard_Input return File_Type is
1820 begin
1821 return Standard_In;
1822 end Standard_Input;
1824 function Standard_Input return File_Access is
1825 begin
1826 return Standard_In'Access;
1827 end Standard_Input;
1829 ---------------------
1830 -- Standard_Output --
1831 ---------------------
1833 function Standard_Output return File_Type is
1834 begin
1835 return Standard_Out;
1836 end Standard_Output;
1838 function Standard_Output return File_Access is
1839 begin
1840 return Standard_Out'Access;
1841 end Standard_Output;
1843 --------------------
1844 -- Terminate_Line --
1845 --------------------
1847 procedure Terminate_Line (File : File_Type) is
1848 begin
1849 FIO.Check_File_Open (AP (File));
1851 -- For file other than In_File, test for needing to terminate last line
1853 if Mode (File) /= In_File then
1855 -- If not at start of line definition need new line
1857 if File.Col /= 1 then
1858 New_Line (File);
1860 -- For files other than standard error and standard output, we
1861 -- make sure that an empty file has a single line feed, so that
1862 -- it is properly formatted. We avoid this for the standard files
1863 -- because it is too much of a nuisance to have these odd line
1864 -- feeds when nothing has been written to the file.
1866 elsif (File /= Standard_Err and then File /= Standard_Out)
1867 and then (File.Line = 1 and then File.Page = 1)
1868 then
1869 New_Line (File);
1870 end if;
1871 end if;
1872 end Terminate_Line;
1874 ------------
1875 -- Ungetc --
1876 ------------
1878 procedure Ungetc (ch : int; File : File_Type) is
1879 begin
1880 if ch /= EOF then
1881 if ungetc (ch, File.Stream) = EOF then
1882 raise Device_Error;
1883 end if;
1884 end if;
1885 end Ungetc;
1887 -----------
1888 -- Write --
1889 -----------
1891 -- This is the primitive Stream Write routine, used when a Text_IO file
1892 -- is treated directly as a stream using Text_IO.Streams.Stream.
1894 procedure Write
1895 (File : in out Wide_Wide_Text_AFCB;
1896 Item : Stream_Element_Array)
1898 pragma Warnings (Off, File);
1899 -- Because in this implementation we don't need IN OUT, we only read
1901 Siz : constant size_t := Item'Length;
1903 begin
1904 if File.Mode = FCB.In_File then
1905 raise Mode_Error;
1906 end if;
1908 -- Now we do the write. Since this is a text file, it is normally in
1909 -- text mode, but stream data must be written in binary mode, so we
1910 -- temporarily set binary mode for the write, resetting it after.
1911 -- These calls have no effect in a system (like Unix) where there is
1912 -- no distinction between text and binary files.
1914 set_binary_mode (fileno (File.Stream));
1916 if fwrite (Item'Address, 1, Siz, File.Stream) /= Siz then
1917 raise Device_Error;
1918 end if;
1920 set_text_mode (fileno (File.Stream));
1921 end Write;
1923 begin
1924 -- Initialize Standard Files
1926 for J in WC_Encoding_Method loop
1927 if WC_Encoding = WC_Encoding_Letters (J) then
1928 Default_WCEM := J;
1929 end if;
1930 end loop;
1932 Initialize_Standard_Files;
1934 FIO.Chain_File (AP (Standard_In));
1935 FIO.Chain_File (AP (Standard_Out));
1936 FIO.Chain_File (AP (Standard_Err));
1938 end Ada.Wide_Wide_Text_IO;