OSDN Git Service

* 1aexcept.adb, 1aexcept.ads, 1ic.ads, 1ssecsta.adb,
[pf3gnuchains/gcc-fork.git] / gcc / ada / tree_io.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                              T R E E _ I O                               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1992-2002 Free Software Foundation, Inc.          --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNAT was originally developed  by the GNAT team at  New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 with Debug;  use Debug;
35 with Output; use Output;
36 with Unchecked_Conversion;
37
38 package body Tree_IO is
39    Debug_Flag_Tree : Boolean := False;
40    --  Debug flag for debug output from tree read/write
41
42    -------------------------------------------
43    -- Compression Scheme Used for Tree File --
44    -------------------------------------------
45
46    --  We don't just write the data directly, but instead do a mild form
47    --  of compression, since we expect lots of compressible zeroes and
48    --  blanks. The compression scheme is as follows:
49
50    --    00nnnnnn followed by nnnnnn bytes (non compressed data)
51    --    01nnnnnn indicates nnnnnn binary zero bytes
52    --    10nnnnnn indicates nnnnnn ASCII space bytes
53    --    11nnnnnn bbbbbbbb indicates nnnnnnnn occurrences of byte bbbbbbbb
54
55    --  Since we expect many zeroes in trees, and many spaces in sources,
56    --  this compression should be reasonably efficient. We can put in
57    --  something better later on.
58
59    --  Note that this compression applies to the Write_Tree_Data and
60    --  Read_Tree_Data calls, not to the calls to read and write single
61    --  scalar values, which are written in memory format without any
62    --  compression.
63
64    C_Noncomp : constant := 2#00_000000#;
65    C_Zeros   : constant := 2#01_000000#;
66    C_Spaces  : constant := 2#10_000000#;
67    C_Repeat  : constant := 2#11_000000#;
68    --  Codes for compression sequences
69
70    Max_Count : constant := 63;
71    --  Maximum data length for one compression sequence
72
73    --  The above compression scheme applies only to data written with the
74    --  Tree_Write routine and read with Tree_Read. Data written using the
75    --  Tree_Write_Char or Tree_Write_Int routines and read using the
76    --  corresponding input routines is not compressed.
77
78    type Int_Bytes is array (1 .. 4) of Byte;
79    for Int_Bytes'Size use 32;
80
81    function To_Int_Bytes is new Unchecked_Conversion (Int, Int_Bytes);
82    function To_Int       is new Unchecked_Conversion (Int_Bytes, Int);
83
84    ----------------------
85    -- Global Variables --
86    ----------------------
87
88    Tree_FD : File_Descriptor;
89    --  File descriptor for tree
90
91    Buflen : constant Int := 8_192;
92    --  Length of buffer for read and write file data
93
94    Buf : array (Pos range 1 .. Buflen) of Byte;
95    --  Read/write file data buffer
96
97    Bufn : Nat;
98    --  Number of bytes read/written from/to buffer
99
100    Buft : Nat;
101    --  Total number of bytes in input buffer containing valid data. Used only
102    --  for input operations. There is data left to be processed in the buffer
103    --  if Buft > Bufn. A value of zero for Buft means that the buffer is empty.
104
105    -----------------------
106    -- Local Subprograms --
107    -----------------------
108
109    procedure Read_Buffer;
110    --  Reads data into buffer, setting Bufe appropriately
111
112    function Read_Byte return Byte;
113    pragma Inline (Read_Byte);
114    --  Returns next byte from input file, raises Tree_Format_Error if none left
115
116    procedure Write_Buffer;
117    --  Writes out current buffer contents
118
119    procedure Write_Byte (B : Byte);
120    pragma Inline (Write_Byte);
121    --  Write one byte to output buffer, checking for buffer-full condition
122
123    -----------------
124    -- Read_Buffer --
125    -----------------
126
127    procedure Read_Buffer is
128    begin
129       Buft := Int (Read (Tree_FD, Buf (1)'Address, Integer (Buflen)));
130
131       if Buft = 0 then
132          raise Tree_Format_Error;
133       else
134          Bufn := 0;
135       end if;
136    end Read_Buffer;
137
138    ---------------
139    -- Read_Byte --
140    ---------------
141
142    function Read_Byte return Byte is
143    begin
144       if Bufn = Buft then
145          Read_Buffer;
146       end if;
147
148       Bufn := Bufn + 1;
149       return Buf (Bufn);
150    end Read_Byte;
151
152    --------------------
153    -- Tree_Read_Bool --
154    --------------------
155
156    procedure Tree_Read_Bool (B : out Boolean) is
157    begin
158       B := Boolean'Val (Read_Byte);
159
160       if Debug_Flag_Tree then
161          if B then
162             Write_Str ("True");
163          else
164             Write_Str ("False");
165          end if;
166
167          Write_Eol;
168       end if;
169    end Tree_Read_Bool;
170
171    --------------------
172    -- Tree_Read_Char --
173    --------------------
174
175    procedure Tree_Read_Char (C : out Character) is
176    begin
177       C := Character'Val (Read_Byte);
178
179       if Debug_Flag_Tree then
180          Write_Str ("==> transmitting Character = ");
181          Write_Char (C);
182          Write_Eol;
183       end if;
184    end Tree_Read_Char;
185
186    --------------------
187    -- Tree_Read_Data --
188    --------------------
189
190    procedure Tree_Read_Data (Addr : Address; Length : Int) is
191
192       type S is array (Pos) of Byte;
193       --  This is a big array, for which we have to suppress the warning
194
195       type SP is access all S;
196
197       function To_SP is new Unchecked_Conversion (Address, SP);
198
199       Data : constant SP := To_SP (Addr);
200       --  Data buffer to be read as an indexable array of bytes
201
202       OP : Pos := 1;
203       --  Pointer to next byte of data buffer to be read into
204
205       B : Byte;
206       C : Byte;
207       L : Int;
208
209    begin
210       if Debug_Flag_Tree then
211          Write_Str ("==> transmitting ");
212          Write_Int (Length);
213          Write_Str (" data bytes");
214          Write_Eol;
215       end if;
216
217       --  Verify data length
218
219       Tree_Read_Int (L);
220
221       if L /= Length then
222          Write_Str ("==> transmitting, expected ");
223          Write_Int (Length);
224          Write_Str (" bytes, found length = ");
225          Write_Int (L);
226          Write_Eol;
227          raise Tree_Format_Error;
228       end if;
229
230       --  Loop to read data
231
232       while OP <= Length loop
233
234          --  Get compression control character
235
236          B := Read_Byte;
237          C := B and 2#00_111111#;
238          B := B and 2#11_000000#;
239
240          --  Non-repeat case
241
242          if B = C_Noncomp then
243             if Debug_Flag_Tree then
244                Write_Str ("==>    uncompressed:  ");
245                Write_Int (Int (C));
246                Write_Str (", starting at ");
247                Write_Int (OP);
248                Write_Eol;
249             end if;
250
251             for J in 1 .. C loop
252                Data (OP) := Read_Byte;
253                OP := OP + 1;
254             end loop;
255
256          --  Repeated zeroes
257
258          elsif B = C_Zeros then
259             if Debug_Flag_Tree then
260                Write_Str ("==>    zeroes:        ");
261                Write_Int (Int (C));
262                Write_Str (", starting at ");
263                Write_Int (OP);
264                Write_Eol;
265             end if;
266
267             for J in 1 .. C loop
268                Data (OP) := 0;
269                OP := OP + 1;
270             end loop;
271
272          --  Repeated spaces
273
274          elsif B = C_Spaces then
275             if Debug_Flag_Tree then
276                Write_Str ("==>    spaces:        ");
277                Write_Int (Int (C));
278                Write_Str (", starting at ");
279                Write_Int (OP);
280                Write_Eol;
281             end if;
282
283             for J in 1 .. C loop
284                Data (OP) := Character'Pos (' ');
285                OP := OP + 1;
286             end loop;
287
288          --  Specified repeated character
289
290          else -- B = C_Repeat
291             B := Read_Byte;
292
293             if Debug_Flag_Tree then
294                Write_Str ("==>    other char:    ");
295                Write_Int (Int (C));
296                Write_Str (" (");
297                Write_Int (Int (B));
298                Write_Char (')');
299                Write_Str (", starting at ");
300                Write_Int (OP);
301                Write_Eol;
302             end if;
303
304             for J in 1 .. C loop
305                Data (OP) := B;
306                OP := OP + 1;
307             end loop;
308          end if;
309       end loop;
310
311       --  At end of loop, data item must be exactly filled
312
313       if OP /= Length + 1 then
314          raise Tree_Format_Error;
315       end if;
316
317    end Tree_Read_Data;
318
319    --------------------------
320    -- Tree_Read_Initialize --
321    --------------------------
322
323    procedure Tree_Read_Initialize (Desc : File_Descriptor) is
324    begin
325       Buft := 0;
326       Bufn := 0;
327       Tree_FD := Desc;
328       Debug_Flag_Tree := Debug_Flag_5;
329    end Tree_Read_Initialize;
330
331    -------------------
332    -- Tree_Read_Int --
333    -------------------
334
335    procedure Tree_Read_Int (N : out Int) is
336       N_Bytes : Int_Bytes;
337
338    begin
339       for J in 1 .. 4 loop
340          N_Bytes (J) := Read_Byte;
341       end loop;
342
343       N := To_Int (N_Bytes);
344
345       if Debug_Flag_Tree then
346          Write_Str ("==> transmitting Int = ");
347          Write_Int (N);
348          Write_Eol;
349       end if;
350    end Tree_Read_Int;
351
352    -------------------
353    -- Tree_Read_Str --
354    -------------------
355
356    procedure Tree_Read_Str (S : out String_Ptr) is
357       N : Nat;
358
359    begin
360       Tree_Read_Int (N);
361       S := new String (1 .. Natural (N));
362       Tree_Read_Data (S.all (1)'Address, N);
363    end Tree_Read_Str;
364
365    -------------------------
366    -- Tree_Read_Terminate --
367    -------------------------
368
369    procedure Tree_Read_Terminate is
370    begin
371       --  Must be at end of input buffer, so we should get Tree_Format_Error
372       --  if we try to read one more byte, if not, we have a format error.
373
374       declare
375          B : Byte;
376       begin
377          B := Read_Byte;
378       exception
379          when Tree_Format_Error => return;
380       end;
381
382       raise Tree_Format_Error;
383    end Tree_Read_Terminate;
384
385    ---------------------
386    -- Tree_Write_Bool --
387    ---------------------
388
389    procedure Tree_Write_Bool (B : Boolean) is
390    begin
391       if Debug_Flag_Tree then
392          Write_Str ("==> transmitting Boolean = ");
393
394          if B then
395             Write_Str ("True");
396          else
397             Write_Str ("False");
398          end if;
399
400          Write_Eol;
401       end if;
402
403       Write_Byte (Boolean'Pos (B));
404    end Tree_Write_Bool;
405
406    ---------------------
407    -- Tree_Write_Char --
408    ---------------------
409
410    procedure Tree_Write_Char (C : Character) is
411    begin
412       if Debug_Flag_Tree then
413          Write_Str ("==> transmitting Character = ");
414          Write_Char (C);
415          Write_Eol;
416       end if;
417
418       Write_Byte (Character'Pos (C));
419    end Tree_Write_Char;
420
421    ---------------------
422    -- Tree_Write_Data --
423    ---------------------
424
425    procedure Tree_Write_Data (Addr : Address; Length : Int) is
426
427       type S is array (Pos) of Byte;
428       --  This is a big array, for which we have to suppress the warning
429
430       type SP is access all S;
431
432       function To_SP is new Unchecked_Conversion (Address, SP);
433
434       Data : constant SP := To_SP (Addr);
435       --  Pointer to data to be written, converted to array type
436
437       IP : Pos := 1;
438       --  Input buffer pointer, next byte to be processed
439
440       NC : Nat range 0 .. Max_Count := 0;
441       --  Number of bytes of non-compressible sequence
442
443       C  : Byte;
444
445       procedure Write_Non_Compressed_Sequence;
446       --  Output currently collected sequence of non-compressible data
447
448       procedure Write_Non_Compressed_Sequence is
449       begin
450          if NC > 0 then
451             Write_Byte (C_Noncomp + Byte (NC));
452
453             if Debug_Flag_Tree then
454                Write_Str ("==>    uncompressed:  ");
455                Write_Int (NC);
456                Write_Str (", starting at ");
457                Write_Int (IP - NC);
458                Write_Eol;
459             end if;
460
461             for J in reverse 1 .. NC loop
462                Write_Byte (Data (IP - J));
463             end loop;
464
465             NC := 0;
466          end if;
467       end Write_Non_Compressed_Sequence;
468
469    --  Start of processing for Tree_Write_Data
470
471    begin
472       if Debug_Flag_Tree then
473          Write_Str ("==> transmitting ");
474          Write_Int (Length);
475          Write_Str (" data bytes");
476          Write_Eol;
477       end if;
478
479       --  We write the count at the start, so that we can check it on
480       --  the corresponding read to make sure that reads and writes match
481
482       Tree_Write_Int (Length);
483
484       --  Conversion loop
485       --    IP is index of next input character
486       --    NC is number of non-compressible bytes saved up
487
488       loop
489          --  If input is completely processed, then we are all done
490
491          if IP > Length then
492             Write_Non_Compressed_Sequence;
493             return;
494          end if;
495
496          --  Test for compressible sequence, must be at least three identical
497          --  bytes in a row to be worthwhile compressing.
498
499          if IP + 2 <= Length
500            and then Data (IP) = Data (IP + 1)
501            and then Data (IP) = Data (IP + 2)
502          then
503             Write_Non_Compressed_Sequence;
504
505             --  Count length of new compression sequence
506
507             C := 3;
508             IP := IP + 3;
509
510             while IP < Length
511               and then Data (IP) = Data (IP - 1)
512               and then C < Max_Count
513             loop
514                C := C + 1;
515                IP := IP + 1;
516             end loop;
517
518             --  Output compression sequence
519
520             if Data (IP - 1) = 0 then
521                if Debug_Flag_Tree then
522                   Write_Str ("==>    zeroes:        ");
523                   Write_Int (Int (C));
524                   Write_Str (", starting at ");
525                   Write_Int (IP - Int (C));
526                   Write_Eol;
527                end if;
528
529                Write_Byte (C_Zeros + C);
530
531             elsif Data (IP - 1) = Character'Pos (' ') then
532                if Debug_Flag_Tree then
533                   Write_Str ("==>    spaces:        ");
534                   Write_Int (Int (C));
535                   Write_Str (", starting at ");
536                   Write_Int (IP - Int (C));
537                   Write_Eol;
538                end if;
539
540                Write_Byte (C_Spaces + C);
541
542             else
543                if Debug_Flag_Tree then
544                   Write_Str ("==>    other char:    ");
545                   Write_Int (Int (C));
546                   Write_Str (" (");
547                   Write_Int (Int (Data (IP - 1)));
548                   Write_Char (')');
549                   Write_Str (", starting at ");
550                   Write_Int (IP - Int (C));
551                   Write_Eol;
552                end if;
553
554                Write_Byte (C_Repeat + C);
555                Write_Byte (Data (IP - 1));
556             end if;
557
558          --  No compression possible here
559
560          else
561             --  Output non-compressed sequence if at maximum length
562
563             if NC = Max_Count then
564                Write_Non_Compressed_Sequence;
565             end if;
566
567             NC := NC + 1;
568             IP := IP + 1;
569          end if;
570       end loop;
571
572    end Tree_Write_Data;
573
574    ---------------------------
575    -- Tree_Write_Initialize --
576    ---------------------------
577
578    procedure Tree_Write_Initialize (Desc : File_Descriptor) is
579    begin
580       Bufn := 0;
581       Tree_FD := Desc;
582       Set_Standard_Error;
583       Debug_Flag_Tree := Debug_Flag_5;
584    end Tree_Write_Initialize;
585
586    --------------------
587    -- Tree_Write_Int --
588    --------------------
589
590    procedure Tree_Write_Int (N : Int) is
591       N_Bytes : constant Int_Bytes := To_Int_Bytes (N);
592
593    begin
594       if Debug_Flag_Tree then
595          Write_Str ("==> transmitting Int = ");
596          Write_Int (N);
597          Write_Eol;
598       end if;
599
600       for J in 1 .. 4 loop
601          Write_Byte (N_Bytes (J));
602       end loop;
603    end Tree_Write_Int;
604
605    --------------------
606    -- Tree_Write_Str --
607    --------------------
608
609    procedure Tree_Write_Str (S : String_Ptr) is
610    begin
611       Tree_Write_Int (S'Length);
612       Tree_Write_Data (S (1)'Address, S'Length);
613    end Tree_Write_Str;
614
615    --------------------------
616    -- Tree_Write_Terminate --
617    --------------------------
618
619    procedure Tree_Write_Terminate is
620    begin
621       if Bufn > 0 then
622          Write_Buffer;
623       end if;
624    end Tree_Write_Terminate;
625
626    ------------------
627    -- Write_Buffer --
628    ------------------
629
630    procedure Write_Buffer is
631    begin
632       if Integer (Bufn) = Write (Tree_FD, Buf'Address, Integer (Bufn)) then
633          Bufn := 0;
634
635       else
636          Set_Standard_Error;
637          Write_Str ("fatal error: disk full");
638          OS_Exit (2);
639       end if;
640    end Write_Buffer;
641
642    ----------------
643    -- Write_Byte --
644    ----------------
645
646    procedure Write_Byte (B : Byte) is
647    begin
648       Bufn := Bufn + 1;
649       Buf (Bufn) := B;
650
651       if Bufn = Buflen then
652          Write_Buffer;
653       end if;
654    end Write_Byte;
655
656 end Tree_IO;