OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [ada/] [a-witeio.adb] - Blame information for rev 12

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.