home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / tree_io.adb < prev    next >
Text File  |  1996-09-28  |  17KB  |  624 lines

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