From 5a8a3749f46828f1db5cbd6bd55d22ea9e188ab1 Mon Sep 17 00:00:00 2001 From: Jed Barber Date: Sun, 5 Feb 2017 00:43:59 +1100 Subject: CSV package done, sketched out Candidates package --- makefile | 3 + src/candidates.adb | 45 ++++++++++++ src/candidates.ads | 75 ++++++++++++++++++++ src/csv.adb | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/csv.ads | 35 ++++++++++ src/stv.adb | 32 +++++++++ 6 files changed, 386 insertions(+) create mode 100644 src/candidates.adb create mode 100644 src/candidates.ads create mode 100644 src/csv.adb create mode 100644 src/csv.ads create mode 100644 src/stv.adb diff --git a/makefile b/makefile index 9475db8..281f11a 100644 --- a/makefile +++ b/makefile @@ -9,3 +9,6 @@ stv: -hidir build -stubdir build -dumpdir build -o bin/stv +ada: + gnatmake src/stv.adb -Isrc -D build -o bin/adastv + diff --git a/src/candidates.adb b/src/candidates.adb new file mode 100644 index 0000000..3701ffc --- /dev/null +++ b/src/candidates.adb @@ -0,0 +1,45 @@ + + +with Ada.Text_IO; +use Ada.Text_IO; +with CSV; + + +package body Candidates is + + + procedure Read_Candidates + (Data_File, State : in String; + Above_Ballot : out Above_Line_Ballot; + Below_Ballot : out Below_Line_Ballot; + Candidate_List : out Candidate_Vectors.Vector) + is + begin + end Read_Candidate; + + + + + function Lookup + (Above_Ballot : in Above_Line_Ballot; + Index : in Natural) + return CandidateID_Vectors.Vector is + begin + return Above_Ballot.Element (Index); + end Lookup; + + + + + function Lookup + (Below_Ballot : in Below_Line_Ballot; + Index : in Natural) + return CandidateID is + begin + return Below_Ballot.Element (Index); + end Lookup; + + +end Candidates; + + diff --git a/src/candidates.ads b/src/candidates.ads new file mode 100644 index 0000000..90b2425 --- /dev/null +++ b/src/candidates.ads @@ -0,0 +1,75 @@ + + +with Ada.Containers.Vectors; + + +package Candidates is + + + type Candidate is private; + type CandidateID is Natural; + + + type Above_Line_Ballot is private; + type Below_Line_Ballot is private; + + + package Candidate_Vectors is new Ada.Containers.Vectors + (Index_Type => CandidateID, + Element_Type => Candidate); + + + package CandidateID_Vectors is new Ada.Containers.Vectors + (Index_Type => Natural, + Element_Type => CandidateID); + + + procedure Read_Candidates + (Data_File, State : in String; + Above_Ballot : out Above_Line_Ballot; + Below_Ballot : out Below_Line_Ballot; + Candidate_List : out Candidate_Vectors.Vector); + + + function Lookup + (Above_Ballot : in Above_Line_Ballot; + Index : in Natural) + return CandidateID_Vectors.Vector; + + + function Lookup + (Below_Ballot : in Below_Line_Ballot; + Index : in Natural) + return CandidateID; + + +private + + + type Candidate is record + ID : CandidateID; + First_Name : String; + Last_Name : String; + Group : String; + Group_Rank : Natural; + Party : String; + end record; + + + package Above_Line_Ballots is new Ada.Containers.Vectors + (Index_Type => Natural, + Element_Type => CandidateID_Vectors.Vector); + + + package Below_Line_Ballots is new Ada.Containers.Vectors + (Index_Type => Natural, + Element_Type => CandidateID); + + + type Above_Line_Ballot is Above_Line_Ballots.Vector; + type Below_Line_Ballot is Below_Line_Ballots.Vector; + + +end Candidates; + + diff --git a/src/csv.adb b/src/csv.adb new file mode 100644 index 0000000..eab633b --- /dev/null +++ b/src/csv.adb @@ -0,0 +1,196 @@ + + +package body CSV is + + + package SU renames Ada.Strings.Unbounded; + + + + + function Quoted + (Input : in SU.Unbounded_String; + Output : out SU.Unbounded_String; + Remaining : out SU.Unbounded_String) + return Boolean + is + Result : SU.Unbounded_String; + This_In : SU.Unbounded_String; + begin + if SU.Length (Input) > 0 and then + SU.Element (Input, 1) = Quote + then + Result := SU.To_Unbounded_String (0); + This_In := SU.Tail (Input, SU.Length (Input) - 1); + while SU.Length (This_In) > 0 loop + SU.Append (Result, SU.Head (This_In, 1)); + This_In := SU.Tail (This_In, SU.Length (This_In) - 1); + exit when SU.Length (This_In) > 0 and then SU.Element (This_In, 1) = Quote; + end loop; + Output := Result; + Remaining := SU.Tail (This_In, SU.Length (This_In) - 1); + return True; + else + return False; + end if; + end Quoted; + + + + + function Escape_Char + (Input : in SU.Unbounded_String; + Output : out SU.Unbounded_String; + Remaining : out SU.Unbounded_String) + return Boolean is + begin + if SU.Length (Input) > 1 and then + SU.Element (Input, 1) = Escape + then + Output := SU.Unbounded_Slice (Input, 2, 1); + Remaining := SU.Tail (Input, SU.Length (Input) - 2); + return True; + else + return False; + end if; + end Escape_Char; + + + + + function Field_Char + (Input : in SU.Unbounded_String; + Output : out SU.Unbounded_String; + Remaining : out SU.Unbounded_String) + return Boolean is + begin + if SU.Length (Input) > 0 and then + SU.Element (Input, 1) /= Delimiter and then + SU.Element (Input, 1) /= Quote and then + SU.Element (Input, 1) /= Escape + then + Output := SU.Head (Input, 1); + Remaining := SU.Tail (Input, SU.Length (Input) - 1); + return True; + else + return False; + end if; + end Field_Char; + + + + + procedure Field + (Input : in SU.Unbounded_String; + Output : out SU.Unbounded_String; + Remaining : out SU.Unbounded_String) + is + Result : SU.Unbounded_String; + This_In, This_Out, This_Remaining : SU.Unbounded_String; + begin + Result := SU.To_Unbounded_String (0); + This_In := Input; + while + Field_Char (This_In, This_Out, This_Remaining) or else + Escape_Char (This_In, This_Out, This_Remaining) or else + Quoted (This_In, This_Out, This_Remaining) + loop + SU.Append (Result, This_Out); + This_In := This_Remaining; + end loop; + Output := Result; + Remaining := This_In; + end Field; + + + + + function Separator + (Input : in SU.Unbounded_String; + Output : out SU.Unbounded_String; + Remaining : out SU.Unbounded_String) + return Boolean is + begin + if SU.Length (Input) > 0 and then + SU.Element (Input, 1) = Delimiter + then + Output := SU.Head (Input, 1); + Remaining := SU.Tail (Input, SU.Length (Input) - 1); + return True; + else + return False; + end if; + end Separator; + + + + + function Parse_Line + (Input : in String) + return CSV_Record + is + Result : CSV_Record := String_Vectors.Empty_Vector; + This_In, This_Out, This_Remaining : SU.Unbounded_String; + begin + This_In := SU.To_Unbounded_String (Input); + loop + Field (This_In, This_Out, This_Remaining); + Result.Append (This_Out); + This_In := This_Remaining; + exit when not Separator (This_In, This_Out, This_Remaining); + This_In := This_Remaining; + end loop; + return Result; + end Parse_Line; + + + + + function Encode_String + (Input : in SU.Unbounded_String) + return SU.Unbounded_String + is + Result : SU.Unbounded_String; + Elem : Character; + Needs_Quotes : Boolean := False; + begin + Result := SU.To_Unbounded_String (0); + for I in Integer range 1 .. SU.Length (Input) loop + Elem := SU.Element (Input, I); + if Elem = Quote or + Elem = Escape + then + SU.Append (Result, Escape & Elem); + else + SU.Append (Result, Elem); + end if; + if Elem = Delimiter then + Needs_Quotes := True; + end if; + end loop; + if Needs_Quotes then + Result := Quote & Result & Quote; + end if; + return Result; + end Encode_String; + + + + + function Unparse_Record + (Input : in CSV_Record) + return String + is + Result : SU.Unbounded_String; + begin + Result := SU.To_Unbounded_String (0); + for Item of Input loop + SU.Append (Result, Encode_String (Item) & Delimiter); + end loop; + return SU.Slice (Result, 1, SU.Length (Result) - 1); + end Unparse_Record; + + +end CSV; + + diff --git a/src/csv.ads b/src/csv.ads new file mode 100644 index 0000000..a8273f5 --- /dev/null +++ b/src/csv.ads @@ -0,0 +1,35 @@ + + +with Ada.Strings.Unbounded; +with Ada.Containers.Vectors; +use type Ada.Strings.Unbounded.Unbounded_String; + + +generic + Delimiter : in Character := ','; + Quote : in Character := '"'; + Escape : in Character := '\'; +package CSV is + + + package String_Vectors is new Ada.Containers.Vectors + (Index_Type => Natural, + Element_Type => Ada.Strings.Unbounded.Unbounded_String); + + + subtype CSV_Record is String_Vectors.Vector; + + + function Parse_Line + (Input : in String) + return CSV_Record; + + + function Unparse_Record + (Input : in CSV_Record) + return String; + + +end CSV; + + diff --git a/src/stv.adb b/src/stv.adb new file mode 100644 index 0000000..3297da2 --- /dev/null +++ b/src/stv.adb @@ -0,0 +1,32 @@ + + +with Ada.Text_IO; +with Ada.Strings.Unbounded; +with CSV; + + +procedure STV is + + + package My_CSV is new CSV; + + + Result : My_CSV.CSV_Record; + + +begin + + + Result := My_CSV.Parse_Line ("123,4""56,78""9764,3,""4,5"","); + + + for Item of Result loop + Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (Item)); + end loop; + + + Ada.Text_IO.Put_Line (My_CSV.Unparse_Record (Result)); + +end STV; + + -- cgit