Search code examples
data-structuresada

How to conveniently parse a very specific chunk of a plaintext file in Ada?


I'm trying to read a URI Extension Block of a Share from Tahoe-LAFS in Ada. It looks something like this:

codec_name:3:crs,codec_params:11:131073-3-10,crypttext_hash:32:..G.3u1~A..o;.w..k,..3.h....K.gk,crypttext_root_hash:32:.}...I3P..Z...A.....tkq.{..'...G,needed_shares:1:3,num_segments:2:52,segment_size:6:131073,share_root_hash:32:.Q>.hGmr.9^J..........size:7:6694675,tail_codec_params:9:9954-3-10,total_shares:2:10,

Now, I was trying to come up with a solution how to get it into a Record type, but I didn't succeed. I thought of a few:

  1. Get all the values into a Map(String)String and after that cast them into their actual types.
  2. Check for the first component of the value, and process it immediately with a switch case statement

Solution

  • You seem to have a string with the structure

    field{,field}
    

    where field is structured

    <name>:<length>:<value>
    

    and <value> is <length> characters long. This is easily parsed using Ada.Strings.Fixed.Index from the standard library:

    function Parsed (Line : in String) return Whatever is
       Result  : Whatever;
       Start   : Positive := Line'First;
       Colon_1 : Positive; -- Constraint_Error will be raised if a colon is missing
       Colon_2 : Positive;
    begin -- Parsed;
       All_Fields : loop
          exit All_Fields when Start > Line'Last;
    
          Colon_1 := Ada.Strings.Fixed.Index (Line, ":", Start);
          Colon_2 := Ada.Strings.Fixed.Index (Line, ":", Colon_1 + 1);
    
          One_Field : declare
             Name   : constant String   := Line (Start .. Colon_1 - 1);
             Length : constant Positive := Integer'Value (Line (Colon_1 + 1 .. Colon_2 - 1) );
             Value  : constant String   := Line (Colon_2 + 1 .. Colon_2 + Length);
          begin -- One_Field
             -- Update Result using Name and Value
             Start := Colon_2 + Length + 2;
          end One_Field;
       end loop All_Fields;
    
       return Result;
    end Parsed;