OSDN Git Service

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