with Ada.Characters.Latin_1, Ada.Characters.Handling, GNAT.Command_Line, GNAT.Strings, Ada.Command_Line, Ada.Directories, Ada.Strings.Unbounded, Ada.Text_IO, UnZip; use Ada.Text_IO; procedure Deck_Convert is package Latin renames Ada.Characters.Latin_1; package Charhand renames Ada.Characters.Handling; package ACom renames Ada.Command_Line; package GCom renames GNAT.Command_Line; package GStr renames GNAT.Strings; package File renames Ada.Directories; package SU renames Ada.Strings.Unbounded; use type File.File_Kind; use type SU.Unbounded_String; function "+" (S : in String) return SU.Unbounded_String renames SU.To_Unbounded_String; function "-" (US : in SU.Unbounded_String) return String renames SU.To_String; Config : GCom.Command_Line_Configuration; Further_Help : String := "Try ""deckconv --help"" for more information."; Verbose : aliased Boolean; Help : aliased Boolean; Overwrite : aliased Boolean; Output_Format : aliased GStr.String_Access; Input_Name : aliased GStr.String_Access; Output_Name : aliased GStr.String_Access; Temp : File_Type; Temp_Name : SU.Unbounded_String; begin GCom.Define_Switch (Config => Config, Output => Verbose'Access, Switch => "-v", Long_Switch => "--verbose", Help => "chatty output on stderr"); GCom.Define_Switch (Config => Config, Output => Help'Access, Switch => "-h", Long_Switch => "--help", Help => "show this help information"); GCom.Define_Switch (Config => Config, Output => Overwrite'Access, Switch => "-f", Long_Switch => "--force", Help => "overwrite selected output file if present"); GCom.Define_Switch (Config => Config, Output => Output_Format'Access, Switch => "-t:", Long_Switch => "--type=", Help => "format of output data, valid options are CSV or FMD"); GCom.Define_Switch (Config => Config, Output => Input_Name'Access, Switch => "-i:", Long_Switch => "--input=", Help => "file name of input deck"); GCom.Define_Switch (Config => Config, Output => Output_Name'Access, Switch => "-o:", Long_Switch => "--output=", Help => "file name to store output data"); GCom.Set_Usage (Config => Config, Usage => "[switches]", Help => "Utility to convert Anki flashcard decks to Fresh Memory dictionaries." & Latin.LF & "At minimum the type, input, and output options are required." & Latin.LF); begin GCom.Getopt (Config); exception when GCom.Exit_From_Command_Line => ACom.Set_Exit_Status (ACom.Failure); return; when GCom.Invalid_Switch => ACom.Set_Exit_Status (ACom.Failure); return; end; if Charhand.To_Upper (Output_Format.all) /= "CSV" and Charhand.To_Upper (Output_Format.all) /= "FMD" then Put_Line (Standard_Error, Output_Format.all); Put_Line (Standard_Error, "Output deck format required. Valid options are CSV or FMD." & Latin.LF & Further_Help); ACom.Set_Exit_Status (ACom.Failure); return; end if; if Input_Name.all = "" then Put_Line (Standard_Error, "File name of input deck was not provided." & Latin.LF & Further_Help); ACom.Set_Exit_Status (ACom.Failure); return; end if; if not File.Exists (Input_Name.all) then Put_Line (Standard_Error, "Input deck does not exist." & Latin.LF & Further_Help); ACom.Set_Exit_Status (ACom.Failure); return; end if; if Output_Name.all = "" then Put_Line (Standard_Error, "File name for output deck was not provided." & Latin.LF & Further_Help); ACom.Set_Exit_Status (ACom.Failure); return; end if; if File.Exists (Output_Name.all) and not Overwrite then Put_Line (Standard_Error, "Output deck file name already exists." & Latin.LF & Further_Help); ACom.Set_Exit_Status (ACom.Failure); return; end if; if File.Exists ("collection.anki2") and not Overwrite then Put_Line (Standard_Error, "Temporary collection.anki2 file already exists." & Latin.LF & Further_Help); ACom.Set_Exit_Status (ACom.Failure); return; end if; -- Generate a temporary filename Create (File => Temp); Temp_Name := +Name (Temp); Close (Temp); UnZip.Extract (Input_Name.all, "collection.anki2", (-Temp_Name)); Put_Line ("Extracted collection as " & (-Temp_Name)); File.Delete_File (-Temp_Name); end Deck_Convert;