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

Subversion Repositories scarts

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

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

powered by: WebSVN 2.1.0

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