* config/arm/elf.h (ASM_OUTPUT_ALIGNED_COMMON): Remove definition.
[official-gcc.git] / gcc / ada / a-witeio.adb
blob4a986301971f80cd188c65cf7eb6e31eab262f8b
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUNTIME COMPONENTS --
4 -- --
5 -- A D A . W I D E _ T E X T _ I O --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2001 Free Software Foundation, Inc. --
10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
21 -- --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
28 -- --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
31 -- --
32 ------------------------------------------------------------------------------
34 with Ada.Exceptions; use Ada.Exceptions;
35 with Ada.Streams; use Ada.Streams;
36 with Interfaces.C_Streams; use Interfaces.C_Streams;
38 with System;
39 with System.File_IO;
40 with System.WCh_Cnv; use System.WCh_Cnv;
41 with System.WCh_Con; use System.WCh_Con;
42 with Unchecked_Conversion;
43 with Unchecked_Deallocation;
45 pragma Elaborate_All (System.File_IO);
46 -- Needed because of calls to Chain_File in package body elaboration
48 package body Ada.Wide_Text_IO is
50 package FIO renames System.File_IO;
52 subtype AP is FCB.AFCB_Ptr;
54 function To_FCB is new Unchecked_Conversion (File_Mode, FCB.File_Mode);
55 function To_TIO is new Unchecked_Conversion (FCB.File_Mode, File_Mode);
56 use type FCB.File_Mode;
58 WC_Encoding : Character;
59 pragma Import (C, WC_Encoding, "__gl_wc_encoding");
61 -----------------------
62 -- Local Subprograms --
63 -----------------------
65 function Getc_Immed (File : in File_Type) return int;
66 -- This routine is identical to Getc, except that the read is done in
67 -- Get_Immediate mode (i.e. without waiting for a line return).
69 function Get_Wide_Char_Immed
70 (C : Character;
71 File : File_Type)
72 return Wide_Character;
73 -- This routine is identical to Get_Wide_Char, except that the reads are
74 -- done in Get_Immediate mode (i.e. without waiting for a line return).
76 procedure Set_WCEM (File : in out File_Type);
77 -- Called by Open and Create to set the wide character encoding method
78 -- for the file, processing a WCEM form parameter if one is present.
79 -- File is IN OUT because it may be closed in case of an error.
81 -------------------
82 -- AFCB_Allocate --
83 -------------------
85 function AFCB_Allocate
86 (Control_Block : Wide_Text_AFCB)
87 return FCB.AFCB_Ptr
89 pragma Warnings (Off, Control_Block);
91 begin
92 return new Wide_Text_AFCB;
93 end AFCB_Allocate;
95 ----------------
96 -- AFCB_Close --
97 ----------------
99 procedure AFCB_Close (File : access Wide_Text_AFCB) is
100 begin
101 -- If the file being closed is one of the current files, then close
102 -- the corresponding current file. It is not clear that this action
103 -- is required (RM A.10.3(23)) but it seems reasonable, and besides
104 -- ACVC test CE3208A expects this behavior.
106 if File_Type (File) = Current_In then
107 Current_In := null;
108 elsif File_Type (File) = Current_Out then
109 Current_Out := null;
110 elsif File_Type (File) = Current_Err then
111 Current_Err := null;
112 end if;
114 Terminate_Line (File_Type (File));
115 end AFCB_Close;
117 ---------------
118 -- AFCB_Free --
119 ---------------
121 procedure AFCB_Free (File : access Wide_Text_AFCB) is
122 type FCB_Ptr is access all Wide_Text_AFCB;
123 FT : FCB_Ptr := FCB_Ptr (File);
125 procedure Free is new Unchecked_Deallocation (Wide_Text_AFCB, FCB_Ptr);
127 begin
128 Free (FT);
129 end AFCB_Free;
131 -----------
132 -- Close --
133 -----------
135 procedure Close (File : in out File_Type) is
136 begin
137 FIO.Close (AP (File));
138 end Close;
140 ---------
141 -- Col --
142 ---------
144 -- Note: we assume that it is impossible in practice for the column
145 -- to exceed the value of Count'Last, i.e. no check is required for
146 -- overflow raising layout error.
148 function Col (File : in File_Type) return Positive_Count is
149 begin
150 FIO.Check_File_Open (AP (File));
151 return File.Col;
152 end Col;
154 function Col return Positive_Count is
155 begin
156 return Col (Current_Out);
157 end Col;
159 ------------
160 -- Create --
161 ------------
163 procedure Create
164 (File : in out File_Type;
165 Mode : in File_Mode := Out_File;
166 Name : in String := "";
167 Form : in String := "")
169 File_Control_Block : Wide_Text_AFCB;
171 begin
172 FIO.Open (File_Ptr => AP (File),
173 Dummy_FCB => File_Control_Block,
174 Mode => To_FCB (Mode),
175 Name => Name,
176 Form => Form,
177 Amethod => 'W',
178 Creat => True,
179 Text => True);
180 Set_WCEM (File);
181 end Create;
183 -------------------
184 -- Current_Error --
185 -------------------
187 function Current_Error return File_Type is
188 begin
189 return Current_Err;
190 end Current_Error;
192 function Current_Error return File_Access is
193 begin
194 return Current_Err'Access;
195 end Current_Error;
197 -------------------
198 -- Current_Input --
199 -------------------
201 function Current_Input return File_Type is
202 begin
203 return Current_In;
204 end Current_Input;
206 function Current_Input return File_Access is
207 begin
208 return Current_In'Access;
209 end Current_Input;
211 --------------------
212 -- Current_Output --
213 --------------------
215 function Current_Output return File_Type is
216 begin
217 return Current_Out;
218 end Current_Output;
220 function Current_Output return File_Access is
221 begin
222 return Current_Out'Access;
223 end Current_Output;
225 ------------
226 -- Delete --
227 ------------
229 procedure Delete (File : in out File_Type) is
230 begin
231 FIO.Delete (AP (File));
232 end Delete;
234 -----------------
235 -- End_Of_File --
236 -----------------
238 function End_Of_File (File : in File_Type) return Boolean is
239 ch : int;
241 begin
242 FIO.Check_Read_Status (AP (File));
244 if File.Before_Wide_Character then
245 return False;
247 elsif File.Before_LM then
249 if File.Before_LM_PM then
250 return Nextc (File) = EOF;
251 end if;
253 else
254 ch := Getc (File);
256 if ch = EOF then
257 return True;
259 elsif ch /= LM then
260 Ungetc (ch, File);
261 return False;
263 else -- ch = LM
264 File.Before_LM := True;
265 end if;
266 end if;
268 -- Here we are just past the line mark with Before_LM set so that we
269 -- do not have to try to back up past the LM, thus avoiding the need
270 -- to back up more than one character.
272 ch := Getc (File);
274 if ch = EOF then
275 return True;
277 elsif ch = PM and then File.Is_Regular_File then
278 File.Before_LM_PM := True;
279 return Nextc (File) = EOF;
281 -- Here if neither EOF nor PM followed end of line
283 else
284 Ungetc (ch, File);
285 return False;
286 end if;
288 end End_Of_File;
290 function End_Of_File return Boolean is
291 begin
292 return End_Of_File (Current_In);
293 end End_Of_File;
295 -----------------
296 -- End_Of_Line --
297 -----------------
299 function End_Of_Line (File : in File_Type) return Boolean is
300 ch : int;
302 begin
303 FIO.Check_Read_Status (AP (File));
305 if File.Before_Wide_Character then
306 return False;
308 elsif File.Before_LM then
309 return True;
311 else
312 ch := Getc (File);
314 if ch = EOF then
315 return True;
317 else
318 Ungetc (ch, File);
319 return (ch = LM);
320 end if;
321 end if;
322 end End_Of_Line;
324 function End_Of_Line return Boolean is
325 begin
326 return End_Of_Line (Current_In);
327 end End_Of_Line;
329 -----------------
330 -- End_Of_Page --
331 -----------------
333 function End_Of_Page (File : in File_Type) return Boolean is
334 ch : int;
336 begin
337 FIO.Check_Read_Status (AP (File));
339 if not File.Is_Regular_File then
340 return False;
342 elsif File.Before_Wide_Character then
343 return False;
345 elsif File.Before_LM then
346 if File.Before_LM_PM then
347 return True;
348 end if;
350 else
351 ch := Getc (File);
353 if ch = EOF then
354 return True;
356 elsif ch /= LM then
357 Ungetc (ch, File);
358 return False;
360 else -- ch = LM
361 File.Before_LM := True;
362 end if;
363 end if;
365 -- Here we are just past the line mark with Before_LM set so that we
366 -- do not have to try to back up past the LM, thus avoiding the need
367 -- to back up more than one character.
369 ch := Nextc (File);
371 return ch = PM or else ch = EOF;
372 end End_Of_Page;
374 function End_Of_Page return Boolean is
375 begin
376 return End_Of_Page (Current_In);
377 end End_Of_Page;
379 -----------
380 -- Flush --
381 -----------
383 procedure Flush (File : in File_Type) is
384 begin
385 FIO.Flush (AP (File));
386 end Flush;
388 procedure Flush is
389 begin
390 Flush (Current_Out);
391 end Flush;
393 ----------
394 -- Form --
395 ----------
397 function Form (File : in File_Type) return String is
398 begin
399 return FIO.Form (AP (File));
400 end Form;
402 ---------
403 -- Get --
404 ---------
406 procedure Get
407 (File : in File_Type;
408 Item : out Wide_Character)
410 C : Character;
412 begin
413 FIO.Check_Read_Status (AP (File));
415 if File.Before_Wide_Character then
416 File.Before_Wide_Character := False;
417 Item := File.Saved_Wide_Character;
419 else
420 Get_Character (File, C);
421 Item := Get_Wide_Char (C, File);
422 end if;
423 end Get;
425 procedure Get (Item : out Wide_Character) is
426 begin
427 Get (Current_In, Item);
428 end Get;
430 procedure Get
431 (File : in File_Type;
432 Item : out Wide_String)
434 begin
435 for J in Item'Range loop
436 Get (File, Item (J));
437 end loop;
438 end Get;
440 procedure Get (Item : out Wide_String) is
441 begin
442 Get (Current_In, Item);
443 end Get;
445 -------------------
446 -- Get_Character --
447 -------------------
449 procedure Get_Character
450 (File : in File_Type;
451 Item : out Character)
453 ch : int;
455 begin
456 if File.Before_LM then
457 File.Before_LM := False;
458 File.Before_LM_PM := False;
459 File.Col := 1;
461 if File.Before_LM_PM then
462 File.Line := 1;
463 File.Page := File.Page + 1;
464 File.Before_LM_PM := False;
466 else
467 File.Line := File.Line + 1;
468 end if;
469 end if;
471 loop
472 ch := Getc (File);
474 if ch = EOF then
475 raise End_Error;
477 elsif ch = LM then
478 File.Line := File.Line + 1;
479 File.Col := 1;
481 elsif ch = PM and then File.Is_Regular_File then
482 File.Page := File.Page + 1;
483 File.Line := 1;
485 else
486 Item := Character'Val (ch);
487 File.Col := File.Col + 1;
488 return;
489 end if;
490 end loop;
491 end Get_Character;
493 -------------------
494 -- Get_Immediate --
495 -------------------
497 procedure Get_Immediate
498 (File : in File_Type;
499 Item : out Wide_Character)
501 ch : int;
503 begin
504 FIO.Check_Read_Status (AP (File));
506 if File.Before_Wide_Character then
507 File.Before_Wide_Character := False;
508 Item := File.Saved_Wide_Character;
510 elsif File.Before_LM then
511 File.Before_LM := False;
512 File.Before_LM_PM := False;
513 Item := Wide_Character'Val (LM);
515 else
516 ch := Getc_Immed (File);
518 if ch = EOF then
519 raise End_Error;
520 else
521 Item := Get_Wide_Char_Immed (Character'Val (ch), File);
522 end if;
523 end if;
524 end Get_Immediate;
526 procedure Get_Immediate
527 (Item : out Wide_Character)
529 begin
530 Get_Immediate (Current_In, Item);
531 end Get_Immediate;
533 procedure Get_Immediate
534 (File : in File_Type;
535 Item : out Wide_Character;
536 Available : out Boolean)
538 ch : int;
540 begin
541 FIO.Check_Read_Status (AP (File));
542 Available := True;
544 if File.Before_Wide_Character then
545 File.Before_Wide_Character := False;
546 Item := File.Saved_Wide_Character;
548 elsif File.Before_LM then
549 File.Before_LM := False;
550 File.Before_LM_PM := False;
551 Item := Wide_Character'Val (LM);
553 else
554 ch := Getc_Immed (File);
556 if ch = EOF then
557 raise End_Error;
558 else
559 Item := Get_Wide_Char_Immed (Character'Val (ch), File);
560 end if;
561 end if;
562 end Get_Immediate;
564 procedure Get_Immediate
565 (Item : out Wide_Character;
566 Available : out Boolean)
568 begin
569 Get_Immediate (Current_In, Item, Available);
570 end Get_Immediate;
572 --------------
573 -- Get_Line --
574 --------------
576 procedure Get_Line
577 (File : in File_Type;
578 Item : out Wide_String;
579 Last : out Natural)
581 begin
582 FIO.Check_Read_Status (AP (File));
583 Last := Item'First - 1;
585 -- Immediate exit for null string, this is a case in which we do not
586 -- need to test for end of file and we do not skip a line mark under
587 -- any circumstances.
589 if Last >= Item'Last then
590 return;
591 end if;
593 -- Here we have at least one character, if we are immediately before
594 -- a line mark, then we will just skip past it storing no characters.
596 if File.Before_LM then
597 File.Before_LM := False;
598 File.Before_LM_PM := False;
600 -- Otherwise we need to read some characters
602 else
603 -- If we are at the end of file now, it means we are trying to
604 -- skip a file terminator and we raise End_Error (RM A.10.7(20))
606 if Nextc (File) = EOF then
607 raise End_Error;
608 end if;
610 -- Loop through characters in string
612 loop
613 -- Exit the loop if read is terminated by encountering line mark
614 -- Note that the use of Skip_Line here ensures we properly deal
615 -- with setting the page and line numbers.
617 if End_Of_Line (File) then
618 Skip_Line (File);
619 return;
620 end if;
622 -- Otherwise store the character, note that we know that ch is
623 -- something other than LM or EOF. It could possibly be a page
624 -- mark if there is a stray page mark in the middle of a line,
625 -- but this is not an official page mark in any case, since
626 -- official page marks can only follow a line mark. The whole
627 -- page business is pretty much nonsense anyway, so we do not
628 -- want to waste time trying to make sense out of non-standard
629 -- page marks in the file! This means that the behavior of
630 -- Get_Line is different from repeated Get of a character, but
631 -- that's too bad. We only promise that page numbers etc make
632 -- sense if the file is formatted in a standard manner.
634 -- Note: we do not adjust the column number because it is quicker
635 -- to adjust it once at the end of the operation than incrementing
636 -- it each time around the loop.
638 Last := Last + 1;
639 Get (File, Item (Last));
641 -- All done if the string is full, this is the case in which
642 -- we do not skip the following line mark. We need to adjust
643 -- the column number in this case.
645 if Last = Item'Last then
646 File.Col := File.Col + Count (Item'Length);
647 return;
648 end if;
650 -- Exit from the loop if we are at the end of file. This happens
651 -- if we have a last line that is not terminated with a line mark.
652 -- In this case we consider that there is an implied line mark;
653 -- this is a non-standard file, but we will treat it nicely.
655 exit when Nextc (File) = EOF;
656 end loop;
657 end if;
658 end Get_Line;
660 procedure Get_Line
661 (Item : out Wide_String;
662 Last : out Natural)
664 begin
665 Get_Line (Current_In, Item, Last);
666 end Get_Line;
668 -------------------
669 -- Get_Wide_Char --
670 -------------------
672 function Get_Wide_Char
673 (C : Character;
674 File : File_Type)
675 return Wide_Character
677 function In_Char return Character;
678 -- Function used to obtain additional characters it the wide character
679 -- sequence is more than one character long.
681 function In_Char return Character is
682 ch : constant Integer := Getc (File);
684 begin
685 if ch = EOF then
686 raise End_Error;
687 else
688 return Character'Val (ch);
689 end if;
690 end In_Char;
692 function WC_In is new Char_Sequence_To_Wide_Char (In_Char);
694 begin
695 return WC_In (C, File.WC_Method);
696 end Get_Wide_Char;
698 -------------------------
699 -- Get_Wide_Char_Immed --
700 -------------------------
702 function Get_Wide_Char_Immed
703 (C : Character;
704 File : File_Type)
705 return Wide_Character
707 function In_Char return Character;
708 -- Function used to obtain additional characters it the wide character
709 -- sequence is more than one character long.
711 function In_Char return Character is
712 ch : constant Integer := Getc_Immed (File);
714 begin
715 if ch = EOF then
716 raise End_Error;
717 else
718 return Character'Val (ch);
719 end if;
720 end In_Char;
722 function WC_In is new Char_Sequence_To_Wide_Char (In_Char);
724 begin
725 return WC_In (C, File.WC_Method);
726 end Get_Wide_Char_Immed;
728 ----------
729 -- Getc --
730 ----------
732 function Getc (File : File_Type) return int is
733 ch : int;
735 begin
736 ch := fgetc (File.Stream);
738 if ch = EOF and then ferror (File.Stream) /= 0 then
739 raise Device_Error;
740 else
741 return ch;
742 end if;
743 end Getc;
745 ----------------
746 -- Getc_Immed --
747 ----------------
749 function Getc_Immed (File : in File_Type) return int is
750 ch : int;
751 end_of_file : int;
753 procedure getc_immediate
754 (stream : FILEs; ch : out int; end_of_file : out int);
755 pragma Import (C, getc_immediate, "getc_immediate");
757 begin
758 FIO.Check_Read_Status (AP (File));
760 if File.Before_LM then
761 File.Before_LM := False;
762 File.Before_LM_PM := False;
763 ch := LM;
765 else
766 getc_immediate (File.Stream, ch, end_of_file);
768 if ferror (File.Stream) /= 0 then
769 raise Device_Error;
770 elsif end_of_file /= 0 then
771 return EOF;
772 end if;
773 end if;
775 return ch;
776 end Getc_Immed;
778 -------------
779 -- Is_Open --
780 -------------
782 function Is_Open (File : in File_Type) return Boolean is
783 begin
784 return FIO.Is_Open (AP (File));
785 end Is_Open;
787 ----------
788 -- Line --
789 ----------
791 -- Note: we assume that it is impossible in practice for the line
792 -- to exceed the value of Count'Last, i.e. no check is required for
793 -- overflow raising layout error.
795 function Line (File : in File_Type) return Positive_Count is
796 begin
797 FIO.Check_File_Open (AP (File));
798 return File.Line;
799 end Line;
801 function Line return Positive_Count is
802 begin
803 return Line (Current_Out);
804 end Line;
806 -----------------
807 -- Line_Length --
808 -----------------
810 function Line_Length (File : in File_Type) return Count is
811 begin
812 FIO.Check_Write_Status (AP (File));
813 return File.Line_Length;
814 end Line_Length;
816 function Line_Length return Count is
817 begin
818 return Line_Length (Current_Out);
819 end Line_Length;
821 ----------------
822 -- Look_Ahead --
823 ----------------
825 procedure Look_Ahead
826 (File : in File_Type;
827 Item : out Wide_Character;
828 End_Of_Line : out Boolean)
830 ch : int;
832 -- Start of processing for Look_Ahead
834 begin
835 FIO.Check_Read_Status (AP (File));
837 -- If we are logically before a line mark, we can return immediately
839 if File.Before_LM then
840 End_Of_Line := True;
841 Item := Wide_Character'Val (0);
843 -- If we are before a wide character, just return it (this happens
844 -- if there are two calls to Look_Ahead in a row).
846 elsif File.Before_Wide_Character then
847 End_Of_Line := False;
848 Item := File.Saved_Wide_Character;
850 -- otherwise we must read a character from the input stream
852 else
853 ch := Getc (File);
855 if ch = LM
856 or else ch = EOF
857 or else (ch = EOF and then File.Is_Regular_File)
858 then
859 End_Of_Line := True;
860 Ungetc (ch, File);
861 Item := Wide_Character'Val (0);
863 -- If the character is in the range 16#0000# to 16#007F# it stands
864 -- for itself and occupies a single byte, so we can unget it with
865 -- no difficulty.
867 elsif ch <= 16#0080# then
868 End_Of_Line := False;
869 Ungetc (ch, File);
870 Item := Wide_Character'Val (ch);
872 -- For a character above this range, we read the character, using
873 -- the Get_Wide_Char routine. It may well occupy more than one byte
874 -- so we can't put it back with ungetc. Instead we save it in the
875 -- control block, setting a flag that everyone interested in reading
876 -- characters must test before reading the stream.
878 else
879 Item := Get_Wide_Char (Character'Val (ch), File);
880 End_Of_Line := False;
881 File.Saved_Wide_Character := Item;
882 File.Before_Wide_Character := True;
883 end if;
884 end if;
885 end Look_Ahead;
887 procedure Look_Ahead
888 (Item : out Wide_Character;
889 End_Of_Line : out Boolean)
891 begin
892 Look_Ahead (Current_In, Item, End_Of_Line);
893 end Look_Ahead;
895 ----------
896 -- Mode --
897 ----------
899 function Mode (File : in File_Type) return File_Mode is
900 begin
901 return To_TIO (FIO.Mode (AP (File)));
902 end Mode;
904 ----------
905 -- Name --
906 ----------
908 function Name (File : in File_Type) return String is
909 begin
910 return FIO.Name (AP (File));
911 end Name;
913 --------------
914 -- New_Line --
915 --------------
917 procedure New_Line
918 (File : in File_Type;
919 Spacing : in Positive_Count := 1)
921 begin
922 -- Raise Constraint_Error if out of range value. The reason for this
923 -- explicit test is that we don't want junk values around, even if
924 -- checks are off in the caller.
926 if Spacing not in Positive_Count then
927 raise Constraint_Error;
928 end if;
930 FIO.Check_Write_Status (AP (File));
932 for K in 1 .. Spacing loop
933 Putc (LM, File);
934 File.Line := File.Line + 1;
936 if File.Page_Length /= 0
937 and then File.Line > File.Page_Length
938 then
939 Putc (PM, File);
940 File.Line := 1;
941 File.Page := File.Page + 1;
942 end if;
943 end loop;
945 File.Col := 1;
946 end New_Line;
948 procedure New_Line (Spacing : in Positive_Count := 1) is
949 begin
950 New_Line (Current_Out, Spacing);
951 end New_Line;
953 --------------
954 -- New_Page --
955 --------------
957 procedure New_Page (File : in File_Type) is
958 begin
959 FIO.Check_Write_Status (AP (File));
961 if File.Col /= 1 or else File.Line = 1 then
962 Putc (LM, File);
963 end if;
965 Putc (PM, File);
966 File.Page := File.Page + 1;
967 File.Line := 1;
968 File.Col := 1;
969 end New_Page;
971 procedure New_Page is
972 begin
973 New_Page (Current_Out);
974 end New_Page;
976 -----------
977 -- Nextc --
978 -----------
980 function Nextc (File : File_Type) return int is
981 ch : int;
983 begin
984 ch := fgetc (File.Stream);
986 if ch = EOF then
987 if ferror (File.Stream) /= 0 then
988 raise Device_Error;
989 end if;
991 else
992 if ungetc (ch, File.Stream) = EOF then
993 raise Device_Error;
994 end if;
995 end if;
997 return ch;
998 end Nextc;
1000 ----------
1001 -- Open --
1002 ----------
1004 procedure Open
1005 (File : in out File_Type;
1006 Mode : in File_Mode;
1007 Name : in String;
1008 Form : in String := "")
1010 File_Control_Block : Wide_Text_AFCB;
1012 begin
1013 FIO.Open (File_Ptr => AP (File),
1014 Dummy_FCB => File_Control_Block,
1015 Mode => To_FCB (Mode),
1016 Name => Name,
1017 Form => Form,
1018 Amethod => 'W',
1019 Creat => False,
1020 Text => True);
1021 Set_WCEM (File);
1022 end Open;
1024 ----------
1025 -- Page --
1026 ----------
1028 -- Note: we assume that it is impossible in practice for the page
1029 -- to exceed the value of Count'Last, i.e. no check is required for
1030 -- overflow raising layout error.
1032 function Page (File : in File_Type) return Positive_Count is
1033 begin
1034 FIO.Check_File_Open (AP (File));
1035 return File.Page;
1036 end Page;
1038 function Page return Positive_Count is
1039 begin
1040 return Page (Current_Out);
1041 end Page;
1043 -----------------
1044 -- Page_Length --
1045 -----------------
1047 function Page_Length (File : in File_Type) return Count is
1048 begin
1049 FIO.Check_Write_Status (AP (File));
1050 return File.Page_Length;
1051 end Page_Length;
1053 function Page_Length return Count is
1054 begin
1055 return Page_Length (Current_Out);
1056 end Page_Length;
1058 ---------
1059 -- Put --
1060 ---------
1062 procedure Put
1063 (File : in File_Type;
1064 Item : in Wide_Character)
1066 procedure Out_Char (C : Character);
1067 -- Procedure to output one character of a wide character sequence
1069 procedure Out_Char (C : Character) is
1070 begin
1071 Putc (Character'Pos (C), File);
1072 end Out_Char;
1074 procedure WC_Out is new Wide_Char_To_Char_Sequence (Out_Char);
1076 begin
1077 WC_Out (Item, File.WC_Method);
1078 File.Col := File.Col + 1;
1079 end Put;
1081 procedure Put (Item : in Wide_Character) is
1082 begin
1083 Put (Current_Out, Item);
1084 end Put;
1086 ---------
1087 -- Put --
1088 ---------
1090 procedure Put
1091 (File : in File_Type;
1092 Item : in Wide_String)
1094 begin
1095 for J in Item'Range loop
1096 Put (File, Item (J));
1097 end loop;
1098 end Put;
1100 procedure Put (Item : in Wide_String) is
1101 begin
1102 Put (Current_Out, Item);
1103 end Put;
1105 --------------
1106 -- Put_Line --
1107 --------------
1109 procedure Put_Line
1110 (File : in File_Type;
1111 Item : in Wide_String)
1113 begin
1114 Put (File, Item);
1115 New_Line (File);
1116 end Put_Line;
1118 procedure Put_Line (Item : in Wide_String) is
1119 begin
1120 Put (Current_Out, Item);
1121 New_Line (Current_Out);
1122 end Put_Line;
1124 ----------
1125 -- Putc --
1126 ----------
1128 procedure Putc (ch : int; File : File_Type) is
1129 begin
1130 if fputc (ch, File.Stream) = EOF then
1131 raise Device_Error;
1132 end if;
1133 end Putc;
1135 ----------
1136 -- Read --
1137 ----------
1139 -- This is the primitive Stream Read routine, used when a Text_IO file
1140 -- is treated directly as a stream using Text_IO.Streams.Stream.
1142 procedure Read
1143 (File : in out Wide_Text_AFCB;
1144 Item : out Stream_Element_Array;
1145 Last : out Stream_Element_Offset)
1147 ch : int;
1149 begin
1150 -- Need to deal with Before_Wide_Character ???
1152 if File.Mode /= FCB.In_File then
1153 raise Mode_Error;
1154 end if;
1156 -- Deal with case where our logical and physical position do not match
1157 -- because of being after an LM or LM-PM sequence when in fact we are
1158 -- logically positioned before it.
1160 if File.Before_LM then
1162 -- If we are before a PM, then it is possible for a stream read
1163 -- to leave us after the LM and before the PM, which is a bit
1164 -- odd. The easiest way to deal with this is to unget the PM,
1165 -- so we are indeed positioned between the characters. This way
1166 -- further stream read operations will work correctly, and the
1167 -- effect on text processing is a little weird, but what can
1168 -- be expected if stream and text input are mixed this way?
1170 if File.Before_LM_PM then
1171 ch := ungetc (PM, File.Stream);
1172 File.Before_LM_PM := False;
1173 end if;
1175 File.Before_LM := False;
1177 Item (Item'First) := Stream_Element (Character'Pos (ASCII.LF));
1179 if Item'Length = 1 then
1180 Last := Item'Last;
1182 else
1183 Last :=
1184 Item'First +
1185 Stream_Element_Offset
1186 (fread (buffer => Item'Address,
1187 index => size_t (Item'First + 1),
1188 size => 1,
1189 count => Item'Length - 1,
1190 stream => File.Stream));
1191 end if;
1193 return;
1194 end if;
1196 -- Now we do the read. Since this is a text file, it is normally in
1197 -- text mode, but stream data must be read in binary mode, so we
1198 -- temporarily set binary mode for the read, resetting it after.
1199 -- These calls have no effect in a system (like Unix) where there is
1200 -- no distinction between text and binary files.
1202 set_binary_mode (fileno (File.Stream));
1204 Last :=
1205 Item'First +
1206 Stream_Element_Offset
1207 (fread (Item'Address, 1, Item'Length, File.Stream)) - 1;
1209 if Last < Item'Last then
1210 if ferror (File.Stream) /= 0 then
1211 raise Device_Error;
1212 end if;
1213 end if;
1215 set_text_mode (fileno (File.Stream));
1216 end Read;
1218 -----------
1219 -- Reset --
1220 -----------
1222 procedure Reset
1223 (File : in out File_Type;
1224 Mode : in File_Mode)
1226 begin
1227 -- Don't allow change of mode for current file (RM A.10.2(5))
1229 if (File = Current_In or else
1230 File = Current_Out or else
1231 File = Current_Error)
1232 and then To_FCB (Mode) /= File.Mode
1233 then
1234 raise Mode_Error;
1235 end if;
1237 Terminate_Line (File);
1238 FIO.Reset (AP (File), To_FCB (Mode));
1239 File.Page := 1;
1240 File.Line := 1;
1241 File.Col := 1;
1242 File.Line_Length := 0;
1243 File.Page_Length := 0;
1244 File.Before_LM := False;
1245 File.Before_LM_PM := False;
1246 end Reset;
1248 procedure Reset (File : in out File_Type) is
1249 begin
1250 Terminate_Line (File);
1251 FIO.Reset (AP (File));
1252 File.Page := 1;
1253 File.Line := 1;
1254 File.Col := 1;
1255 File.Line_Length := 0;
1256 File.Page_Length := 0;
1257 File.Before_LM := False;
1258 File.Before_LM_PM := False;
1259 end Reset;
1261 -------------
1262 -- Set_Col --
1263 -------------
1265 procedure Set_Col
1266 (File : in File_Type;
1267 To : in Positive_Count)
1269 ch : int;
1271 begin
1272 -- Raise Constraint_Error if out of range value. The reason for this
1273 -- explicit test is that we don't want junk values around, even if
1274 -- checks are off in the caller.
1276 if To not in Positive_Count then
1277 raise Constraint_Error;
1278 end if;
1280 FIO.Check_File_Open (AP (File));
1282 if To = File.Col then
1283 return;
1284 end if;
1286 if Mode (File) >= Out_File then
1287 if File.Line_Length /= 0 and then To > File.Line_Length then
1288 raise Layout_Error;
1289 end if;
1291 if To < File.Col then
1292 New_Line (File);
1293 end if;
1295 while File.Col < To loop
1296 Put (File, ' ');
1297 end loop;
1299 else
1300 loop
1301 ch := Getc (File);
1303 if ch = EOF then
1304 raise End_Error;
1306 elsif ch = LM then
1307 File.Line := File.Line + 1;
1308 File.Col := 1;
1310 elsif ch = PM and then File.Is_Regular_File then
1311 File.Page := File.Page + 1;
1312 File.Line := 1;
1313 File.Col := 1;
1315 elsif To = File.Col then
1316 Ungetc (ch, File);
1317 return;
1319 else
1320 File.Col := File.Col + 1;
1321 end if;
1322 end loop;
1323 end if;
1324 end Set_Col;
1326 procedure Set_Col (To : in Positive_Count) is
1327 begin
1328 Set_Col (Current_Out, To);
1329 end Set_Col;
1331 ---------------
1332 -- Set_Error --
1333 ---------------
1335 procedure Set_Error (File : in File_Type) is
1336 begin
1337 FIO.Check_Write_Status (AP (File));
1338 Current_Err := File;
1339 end Set_Error;
1341 ---------------
1342 -- Set_Input --
1343 ---------------
1345 procedure Set_Input (File : in File_Type) is
1346 begin
1347 FIO.Check_Read_Status (AP (File));
1348 Current_In := File;
1349 end Set_Input;
1351 --------------
1352 -- Set_Line --
1353 --------------
1355 procedure Set_Line
1356 (File : in File_Type;
1357 To : in Positive_Count)
1359 begin
1360 -- Raise Constraint_Error if out of range value. The reason for this
1361 -- explicit test is that we don't want junk values around, even if
1362 -- checks are off in the caller.
1364 if To not in Positive_Count then
1365 raise Constraint_Error;
1366 end if;
1368 FIO.Check_File_Open (AP (File));
1370 if To = File.Line then
1371 return;
1372 end if;
1374 if Mode (File) >= Out_File then
1375 if File.Page_Length /= 0 and then To > File.Page_Length then
1376 raise Layout_Error;
1377 end if;
1379 if To < File.Line then
1380 New_Page (File);
1381 end if;
1383 while File.Line < To loop
1384 New_Line (File);
1385 end loop;
1387 else
1388 while To /= File.Line loop
1389 Skip_Line (File);
1390 end loop;
1391 end if;
1392 end Set_Line;
1394 procedure Set_Line (To : in Positive_Count) is
1395 begin
1396 Set_Line (Current_Out, To);
1397 end Set_Line;
1399 ---------------------
1400 -- Set_Line_Length --
1401 ---------------------
1403 procedure Set_Line_Length (File : in File_Type; To : in Count) is
1404 begin
1405 -- Raise Constraint_Error if out of range value. The reason for this
1406 -- explicit test is that we don't want junk values around, even if
1407 -- checks are off in the caller.
1409 if To not in Count then
1410 raise Constraint_Error;
1411 end if;
1413 FIO.Check_Write_Status (AP (File));
1414 File.Line_Length := To;
1415 end Set_Line_Length;
1417 procedure Set_Line_Length (To : in Count) is
1418 begin
1419 Set_Line_Length (Current_Out, To);
1420 end Set_Line_Length;
1422 ----------------
1423 -- Set_Output --
1424 ----------------
1426 procedure Set_Output (File : in File_Type) is
1427 begin
1428 FIO.Check_Write_Status (AP (File));
1429 Current_Out := File;
1430 end Set_Output;
1432 ---------------------
1433 -- Set_Page_Length --
1434 ---------------------
1436 procedure Set_Page_Length (File : in File_Type; To : in Count) is
1437 begin
1438 -- Raise Constraint_Error if out of range value. The reason for this
1439 -- explicit test is that we don't want junk values around, even if
1440 -- checks are off in the caller.
1442 if To not in Count then
1443 raise Constraint_Error;
1444 end if;
1446 FIO.Check_Write_Status (AP (File));
1447 File.Page_Length := To;
1448 end Set_Page_Length;
1450 procedure Set_Page_Length (To : in Count) is
1451 begin
1452 Set_Page_Length (Current_Out, To);
1453 end Set_Page_Length;
1455 --------------
1456 -- Set_WCEM --
1457 --------------
1459 procedure Set_WCEM (File : in out File_Type) is
1460 Start : Natural;
1461 Stop : Natural;
1463 begin
1464 File.WC_Method := WCEM_Brackets;
1465 FIO.Form_Parameter (File.Form.all, "wcem", Start, Stop);
1467 if Start = 0 then
1468 File.WC_Method := WCEM_Brackets;
1470 elsif Start /= 0 then
1471 if Stop = Start then
1472 for J in WC_Encoding_Letters'Range loop
1473 if File.Form (Start) = WC_Encoding_Letters (J) then
1474 File.WC_Method := J;
1475 return;
1476 end if;
1477 end loop;
1478 end if;
1480 Close (File);
1481 Raise_Exception (Use_Error'Identity, "invalid WCEM form parameter");
1482 end if;
1483 end Set_WCEM;
1485 ---------------
1486 -- Skip_Line --
1487 ---------------
1489 procedure Skip_Line
1490 (File : in File_Type;
1491 Spacing : in Positive_Count := 1)
1493 ch : int;
1495 begin
1496 -- Raise Constraint_Error if out of range value. The reason for this
1497 -- explicit test is that we don't want junk values around, even if
1498 -- checks are off in the caller.
1500 if Spacing not in Positive_Count then
1501 raise Constraint_Error;
1502 end if;
1504 FIO.Check_Read_Status (AP (File));
1506 for L in 1 .. Spacing loop
1507 if File.Before_LM then
1508 File.Before_LM := False;
1509 File.Before_LM_PM := False;
1511 else
1512 ch := Getc (File);
1514 -- If at end of file now, then immediately raise End_Error. Note
1515 -- that we can never be positioned between a line mark and a page
1516 -- mark, so if we are at the end of file, we cannot logically be
1517 -- before the implicit page mark that is at the end of the file.
1519 -- For the same reason, we do not need an explicit check for a
1520 -- page mark. If there is a FF in the middle of a line, the file
1521 -- is not in canonical format and we do not care about the page
1522 -- numbers for files other than ones in canonical format.
1524 if ch = EOF then
1525 raise End_Error;
1526 end if;
1528 -- If not at end of file, then loop till we get to an LM or EOF.
1529 -- The latter case happens only in non-canonical files where the
1530 -- last line is not terminated by LM, but we don't want to blow
1531 -- up for such files, so we assume an implicit LM in this case.
1533 loop
1534 exit when ch = LM or ch = EOF;
1535 ch := Getc (File);
1536 end loop;
1537 end if;
1539 -- We have got past a line mark, now, for a regular file only,
1540 -- see if a page mark immediately follows this line mark and
1541 -- if so, skip past the page mark as well. We do not do this
1542 -- for non-regular files, since it would cause an undesirable
1543 -- wait for an additional character.
1545 File.Col := 1;
1546 File.Line := File.Line + 1;
1548 if File.Before_LM_PM then
1549 File.Page := File.Page + 1;
1550 File.Line := 1;
1551 File.Before_LM_PM := False;
1553 elsif File.Is_Regular_File then
1554 ch := Getc (File);
1556 -- Page mark can be explicit, or implied at the end of the file
1558 if (ch = PM or else ch = EOF)
1559 and then File.Is_Regular_File
1560 then
1561 File.Page := File.Page + 1;
1562 File.Line := 1;
1563 else
1564 Ungetc (ch, File);
1565 end if;
1566 end if;
1568 end loop;
1570 File.Before_Wide_Character := False;
1571 end Skip_Line;
1573 procedure Skip_Line (Spacing : in Positive_Count := 1) is
1574 begin
1575 Skip_Line (Current_In, Spacing);
1576 end Skip_Line;
1578 ---------------
1579 -- Skip_Page --
1580 ---------------
1582 procedure Skip_Page (File : in File_Type) is
1583 ch : int;
1585 begin
1586 FIO.Check_Read_Status (AP (File));
1588 -- If at page mark already, just skip it
1590 if File.Before_LM_PM then
1591 File.Before_LM := False;
1592 File.Before_LM_PM := False;
1593 File.Page := File.Page + 1;
1594 File.Line := 1;
1595 File.Col := 1;
1596 return;
1597 end if;
1599 -- This is a bit tricky, if we are logically before an LM then
1600 -- it is not an error if we are at an end of file now, since we
1601 -- are not really at it.
1603 if File.Before_LM then
1604 File.Before_LM := False;
1605 File.Before_LM_PM := False;
1606 ch := Getc (File);
1608 -- Otherwise we do raise End_Error if we are at the end of file now
1610 else
1611 ch := Getc (File);
1613 if ch = EOF then
1614 raise End_Error;
1615 end if;
1616 end if;
1618 -- Now we can just rumble along to the next page mark, or to the
1619 -- end of file, if that comes first. The latter case happens when
1620 -- the page mark is implied at the end of file.
1622 loop
1623 exit when ch = EOF
1624 or else (ch = PM and then File.Is_Regular_File);
1625 ch := Getc (File);
1626 end loop;
1628 File.Page := File.Page + 1;
1629 File.Line := 1;
1630 File.Col := 1;
1631 File.Before_Wide_Character := False;
1632 end Skip_Page;
1634 procedure Skip_Page is
1635 begin
1636 Skip_Page (Current_In);
1637 end Skip_Page;
1639 --------------------
1640 -- Standard_Error --
1641 --------------------
1643 function Standard_Error return File_Type is
1644 begin
1645 return Standard_Err;
1646 end Standard_Error;
1648 function Standard_Error return File_Access is
1649 begin
1650 return Standard_Err'Access;
1651 end Standard_Error;
1653 --------------------
1654 -- Standard_Input --
1655 --------------------
1657 function Standard_Input return File_Type is
1658 begin
1659 return Standard_In;
1660 end Standard_Input;
1662 function Standard_Input return File_Access is
1663 begin
1664 return Standard_In'Access;
1665 end Standard_Input;
1667 ---------------------
1668 -- Standard_Output --
1669 ---------------------
1671 function Standard_Output return File_Type is
1672 begin
1673 return Standard_Out;
1674 end Standard_Output;
1676 function Standard_Output return File_Access is
1677 begin
1678 return Standard_Out'Access;
1679 end Standard_Output;
1681 --------------------
1682 -- Terminate_Line --
1683 --------------------
1685 procedure Terminate_Line (File : File_Type) is
1686 begin
1687 FIO.Check_File_Open (AP (File));
1689 -- For file other than In_File, test for needing to terminate last line
1691 if Mode (File) /= In_File then
1693 -- If not at start of line definition need new line
1695 if File.Col /= 1 then
1696 New_Line (File);
1698 -- For files other than standard error and standard output, we
1699 -- make sure that an empty file has a single line feed, so that
1700 -- it is properly formatted. We avoid this for the standard files
1701 -- because it is too much of a nuisance to have these odd line
1702 -- feeds when nothing has been written to the file.
1704 elsif (File /= Standard_Err and then File /= Standard_Out)
1705 and then (File.Line = 1 and then File.Page = 1)
1706 then
1707 New_Line (File);
1708 end if;
1709 end if;
1710 end Terminate_Line;
1712 ------------
1713 -- Ungetc --
1714 ------------
1716 procedure Ungetc (ch : int; File : File_Type) is
1717 begin
1718 if ch /= EOF then
1719 if ungetc (ch, File.Stream) = EOF then
1720 raise Device_Error;
1721 end if;
1722 end if;
1723 end Ungetc;
1725 -----------
1726 -- Write --
1727 -----------
1729 -- This is the primitive Stream Write routine, used when a Text_IO file
1730 -- is treated directly as a stream using Text_IO.Streams.Stream.
1732 procedure Write
1733 (File : in out Wide_Text_AFCB;
1734 Item : in Stream_Element_Array)
1736 Siz : constant size_t := Item'Length;
1738 begin
1739 if File.Mode = FCB.In_File then
1740 raise Mode_Error;
1741 end if;
1743 -- Now we do the write. Since this is a text file, it is normally in
1744 -- text mode, but stream data must be written in binary mode, so we
1745 -- temporarily set binary mode for the write, resetting it after.
1746 -- These calls have no effect in a system (like Unix) where there is
1747 -- no distinction between text and binary files.
1749 set_binary_mode (fileno (File.Stream));
1751 if fwrite (Item'Address, 1, Siz, File.Stream) /= Siz then
1752 raise Device_Error;
1753 end if;
1755 set_text_mode (fileno (File.Stream));
1756 end Write;
1758 -- Use "preallocated" strings to avoid calling "new" during the
1759 -- elaboration of the run time. This is needed in the tasking case to
1760 -- avoid calling Task_Lock too early. A filename is expected to end with
1761 -- a null character in the runtime, here the null characters are added
1762 -- just to have a correct filename length.
1764 Err_Name : aliased String := "*stderr" & ASCII.Nul;
1765 In_Name : aliased String := "*stdin" & ASCII.Nul;
1766 Out_Name : aliased String := "*stdout" & ASCII.Nul;
1768 begin
1769 -------------------------------
1770 -- Initialize Standard Files --
1771 -------------------------------
1773 for J in WC_Encoding_Method loop
1774 if WC_Encoding = WC_Encoding_Letters (J) then
1775 Default_WCEM := J;
1776 end if;
1777 end loop;
1779 -- Note: the names in these files are bogus, and probably it would be
1780 -- better for these files to have no names, but the ACVC test insist!
1781 -- We use names that are bound to fail in open etc.
1783 Standard_Err.Stream := stderr;
1784 Standard_Err.Name := Err_Name'Access;
1785 Standard_Err.Form := Null_Str'Unrestricted_Access;
1786 Standard_Err.Mode := FCB.Out_File;
1787 Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0;
1788 Standard_Err.Is_Temporary_File := False;
1789 Standard_Err.Is_System_File := True;
1790 Standard_Err.Is_Text_File := True;
1791 Standard_Err.Access_Method := 'T';
1792 Standard_Err.WC_Method := Default_WCEM;
1794 Standard_In.Stream := stdin;
1795 Standard_In.Name := In_Name'Access;
1796 Standard_In.Form := Null_Str'Unrestricted_Access;
1797 Standard_In.Mode := FCB.In_File;
1798 Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0;
1799 Standard_In.Is_Temporary_File := False;
1800 Standard_In.Is_System_File := True;
1801 Standard_In.Is_Text_File := True;
1802 Standard_In.Access_Method := 'T';
1803 Standard_In.WC_Method := Default_WCEM;
1805 Standard_Out.Stream := stdout;
1806 Standard_Out.Name := Out_Name'Access;
1807 Standard_Out.Form := Null_Str'Unrestricted_Access;
1808 Standard_Out.Mode := FCB.Out_File;
1809 Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0;
1810 Standard_Out.Is_Temporary_File := False;
1811 Standard_Out.Is_System_File := True;
1812 Standard_Out.Is_Text_File := True;
1813 Standard_Out.Access_Method := 'T';
1814 Standard_Out.WC_Method := Default_WCEM;
1816 FIO.Chain_File (AP (Standard_In));
1817 FIO.Chain_File (AP (Standard_Out));
1818 FIO.Chain_File (AP (Standard_Err));
1820 FIO.Make_Unbuffered (AP (Standard_Out));
1821 FIO.Make_Unbuffered (AP (Standard_Err));
1823 end Ada.Wide_Text_IO;