From 32a6db11b7e8ca95bac718baac019d19fff03845 Mon Sep 17 00:00:00 2001 From: Jedidiah Barber Date: Sun, 24 Oct 2021 23:42:05 +1300 Subject: Initial commit of mostly boilerplate --- bin/.gitignore | 4 ++ data/.gitignore | 8 +++ freshdeck.gpr | 37 +++++++++++ license.txt | 25 ++++++++ obj/.gitignore | 4 ++ src/deck_convert.adb | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 256 insertions(+) create mode 100644 bin/.gitignore create mode 100644 data/.gitignore create mode 100644 freshdeck.gpr create mode 100644 license.txt create mode 100644 obj/.gitignore create mode 100644 src/deck_convert.adb diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 0000000..ea7f887 --- /dev/null +++ b/bin/.gitignore @@ -0,0 +1,4 @@ + + +* +!.gitignore diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 0000000..fc50a55 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1,8 @@ + + +# ignore all in this directory except this file + +* +!.gitignore + + diff --git a/freshdeck.gpr b/freshdeck.gpr new file mode 100644 index 0000000..f3065e0 --- /dev/null +++ b/freshdeck.gpr @@ -0,0 +1,37 @@ + + +-- with "fltkada"; +with "zipada_lib"; + + +project Freshdeck is + + + for Languages use ("Ada"); + + + for Source_Dirs use ("src/**"); + for Object_Dir use "obj"; + for Exec_Dir use "bin"; + for Main use ("deck_convert.adb"); -- , "deck_convert_gui.adb"); + + + package Builder is + for Executable ("deck_convert.adb") use "deckconv"; + -- for Executable ("deck_convert_gui.adb") use "gdeckconv"; + end Builder; + + + package Compiler is + for Default_Switches("Ada") use ("-gnaty4aAbcefhiklM100nprt"); + end Compiler; + + + -- package Linker is + -- for Default_Switches("Ada") use ("-lfltk", "-lfltk_images"); + -- end Linker; + + +end Freshdeck; + + diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..41c1fae --- /dev/null +++ b/license.txt @@ -0,0 +1,25 @@ + + +SUNSET LICENSE +Version 1.0, June 2017 + + +1. You may copy, modify, use, sell, or distribute this work, verbatim or +modified, for any purpose. + +2. If you sell or distribute this work, whether verbatim or modified, you must +include a copy of this license, and you must make the source code available for +no extra charge. + +3. A modified version of this work must be clearly labeled as such. + +4. Derivative works must also be licensed under this license or a license of +equivalent terms. As an exception, linking this work with another, whether +statically or dynamically, does not impose any license requirements on the +other work. + +5. If a minimum of 15 years have passed since the date of first publishing for +a part of this work, then that part is placed into the public domain and you +may do whatever you want with it, regardless of all other clauses. + + diff --git a/obj/.gitignore b/obj/.gitignore new file mode 100644 index 0000000..ea7f887 --- /dev/null +++ b/obj/.gitignore @@ -0,0 +1,4 @@ + + +* +!.gitignore diff --git a/src/deck_convert.adb b/src/deck_convert.adb new file mode 100644 index 0000000..6d140a4 --- /dev/null +++ b/src/deck_convert.adb @@ -0,0 +1,178 @@ + + +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; + + -- cgit