Skip to content

Commit fc350e8

Browse files
committed
first commit
0 parents  commit fc350e8

File tree

10 files changed

+566
-0
lines changed

10 files changed

+566
-0
lines changed

.envrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
eval $(alr printenv)

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/obj/
2+
/bin/
3+
/alire/
4+
/config/

.vscode/launch.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Debug",
9+
"type": "gdb",
10+
"request": "launch",
11+
"target": "./bin/keypadder",
12+
"arguments": "--config=examples/keypad.toml",
13+
"cwd": "${workspaceRoot}",
14+
"valuesFormatting": "parseText"
15+
}
16+
]
17+
}

LICENSE

+232
Large diffs are not rendered by default.

alire.toml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name = "keypadder"
2+
description = "Shiny new project"
3+
version = "0.1.0-dev"
4+
5+
authors = ["Stephen Merrony"]
6+
maintainers = ["Stephen Merrony <[email protected]>"]
7+
maintainers-logins = ["SMerrony"]
8+
9+
executables = ["keypadder"]
10+
[[depends-on]]
11+
aws = "^23.0.0"
12+
[[depends-on]]
13+
ada_toml = "~0.3.0"

examples/keypad.toml

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
[keypadder]
2+
port = 8082 # HTTP port to use
3+
4+
[[tab]] # A new tab
5+
label = "French"
6+
cols = 3 # No. of columns on this tab
7+
keys = [
8+
{ label = "à", send = "à" },
9+
{ label = "â" },
10+
{ label = "ç" },
11+
# new row will start here
12+
{ label = "è" },
13+
{ label = "ê" },
14+
{ label = "é" },
15+
#
16+
{ label = "ì" },
17+
{ label = "î" },
18+
{ label = "ï" },
19+
#
20+
{ label = "ò" },
21+
{ label = "ô" },
22+
{ label = "ë" },
23+
#
24+
{ label = "ù" },
25+
{ label = "û" },
26+
{ label = "ü" }
27+
]
28+
29+
[[tab]]
30+
label = "MuseScore"
31+
cols = 4
32+
keys = [
33+
{ label = "Esc", send = "\u001b" },
34+
{ label = "\U0001d17b", send = "V" },
35+
{ label = "\U0001d17c", send = "S" },
36+
{ label = "\U0001d17d", send = "N" },
37+
#
38+
{ label = "\u266e", send = "=" },
39+
{ label = "\u266f", send = "+" },
40+
{ label = "\u266d", send = "-" },
41+
{ label = "BLANK" },
42+
#
43+
{ label = "\U0001d1df", send = "5" },
44+
{ label = "\U0001d15f", send = "6" },
45+
{ label = "\U0001d15d", send = "7" },
46+
{ label = "BLANK" },
47+
#
48+
{ label = "\U0001d162", send = "2" },
49+
{ label = "\U0001d161", send = "3" },
50+
{ label = "\U0001d160", send = "4" },
51+
{ label = "\u035c", rowspan = 2, send = "T" },
52+
#
53+
{ label = "\U0001d13d", colspan = 2, send = "0" },
54+
{ label = "." }
55+
]

keypadder.gpr

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
with "config/keypadder_config.gpr";
2+
project Keypadder is
3+
4+
for Source_Dirs use ("src/", "config/");
5+
for Object_Dir use "obj/" & Keypadder_Config.Build_Profile;
6+
for Create_Missing_Dirs use "True";
7+
for Exec_Dir use "bin";
8+
for Main use ("keypadder.adb");
9+
10+
package Compiler is
11+
for Default_Switches ("Ada") use Keypadder_Config.Ada_Compiler_Switches;
12+
end Compiler;
13+
14+
package Binder is
15+
for Switches ("Ada") use ("-Es"); -- Symbolic traceback
16+
end Binder;
17+
18+
package Install is
19+
for Artifacts (".") use ("share");
20+
end Install;
21+
22+
end Keypadder;

src/config.adb

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
-- SPDX-License-Identifier: GPL-3.0-or-later
2+
-- SPDX-FileCopyrightText: Copyright 2023 Stephen Merrony
3+
4+
with Ada.Text_IO; use Ada.Text_IO;
5+
6+
with TOML;
7+
with TOML.File_IO;
8+
9+
package body Config is
10+
11+
procedure Load_Config_File (Filename : String; Verbose : Boolean := False) is
12+
Toml_Parse_Result : TOML.Read_Result;
13+
begin
14+
Toml_Parse_Result := TOML.File_IO.Load_File (Filename);
15+
if not Toml_Parse_Result.Success then
16+
raise Could_Not_Parse with To_String (Toml_Parse_Result.Message);
17+
end if;
18+
19+
declare
20+
Top_Keys : constant TOML.Key_Array := Toml_Parse_Result.Value.Keys;
21+
Tab_Ix : Natural := 0;
22+
begin
23+
for TK of Top_Keys loop
24+
if Verbose then
25+
Put_Line ("Configuration for " & To_String (TK) & " is...");
26+
end if;
27+
28+
if To_String (TK) = "keypadder" then
29+
declare
30+
Keypadder_Table : constant TOML.TOML_Value := TOML.Get (Toml_Parse_Result.Value, "keypadder");
31+
begin
32+
Keypadder_Conf.Port := Port_T (TOML.As_Integer (TOML.Get (Keypadder_Table, "port")));
33+
if Verbose then
34+
Put_Line ("Port:" & Keypadder_Conf.Port'Image);
35+
end if;
36+
end;
37+
elsif To_String (TK) = "tab" then
38+
declare
39+
Tabs_Array : constant TOML.TOML_Value := TOML.Get (Toml_Parse_Result.Value, "tab");
40+
Tabs_Count : constant Natural := TOML.Length (Tabs_Array);
41+
Tab : TOML.TOML_Value;
42+
43+
begin
44+
if Tabs_Count = 0 then
45+
raise Incomplete_Configuration with "you must configure at least one Tab";
46+
end if;
47+
for T in 1 .. Tabs_Count loop
48+
Tab_Ix := Tab_Ix + 1;
49+
Tab := TOML.Item (Tabs_Array, T);
50+
Tabs (T).Label := TOML.As_Unbounded_String (TOML.Get (Tab, "label"));
51+
Tabs (T).Columns := Natural (TOML.As_Integer (TOML.Get (Tab, "cols")));
52+
-- Put_Line ("Tab defined:" & TOML.Dump_As_String (Tab));
53+
if Verbose then
54+
Put_Line ("Tab: " & To_String (Tabs (T).Label) &
55+
" with:" & Tabs (T).Columns'Image & " columns");
56+
end if;
57+
declare
58+
Keys_Array : constant TOML.TOML_Value := TOML.Get (Tab, "keys");
59+
Key_Table : TOML.TOML_Value;
60+
begin
61+
Put_Line ("Keys defined:" & TOML.Length (Keys_Array)'Image);
62+
Tabs (Tab_Ix).Keys_Count := TOML.Length (Keys_Array);
63+
for K in 1 .. TOML.Length (Keys_Array) loop
64+
Key_Table := TOML.Item (Keys_Array, K);
65+
Tabs (Tab_Ix).Keys (K).Label := TOML.As_Unbounded_String (TOML.Get (Key_Table, "label"));
66+
if TOML.Has (Key_Table, "send") then
67+
Tabs (Tab_Ix).Keys (K).Send := TOML.As_Unbounded_String (TOML.Get (Key_Table, "send"));
68+
end if;
69+
if TOML.Has (Key_Table, "colspan") then
70+
Tabs (Tab_Ix).Keys (K).Colspan := Natural (TOML.As_Integer (TOML.Get (Key_Table, "colspan")));
71+
end if;
72+
if TOML.Has (Key_Table, "rowspan") then
73+
Tabs (Tab_Ix).Keys (K).Rowspan := Natural (TOML.As_Integer (TOML.Get (Key_Table, "rowspan")));
74+
end if;
75+
if Verbose then
76+
Put_Line ("Key No. " & K'Image & " is: " & To_String (Tabs (Tab_Ix).Keys (K).Label));
77+
end if;
78+
end loop;
79+
end;
80+
end loop;
81+
end;
82+
else
83+
raise Unknown_Configuration_Item with To_String (TK);
84+
end if;
85+
86+
end loop;
87+
end;
88+
end Load_Config_File;
89+
90+
end Config;

src/config.ads

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
-- SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
4+
5+
package Config is
6+
7+
type Port_T is range 1 .. 65535;
8+
type Keypadder_Conf_T is record
9+
Port : Port_T;
10+
end record;
11+
12+
Keypadder_Conf : Keypadder_Conf_T;
13+
14+
type Key_T is record
15+
Label : Unbounded_String;
16+
Send : Unbounded_String;
17+
Colspan,
18+
Rowspan : Natural := 0;
19+
end record;
20+
21+
Max_Keys : constant Positive := 88;
22+
-- Arbitrary limit to ensure the config parser doesn't go into
23+
-- a crazy loop.
24+
25+
type Keys_T is array (1 .. Max_Keys) of Key_T;
26+
27+
type Tab_T is record
28+
Label : Unbounded_String;
29+
Columns : Natural := 0;
30+
Keys : Keys_T;
31+
Keys_Count : Natural := 0;
32+
end record;
33+
34+
Max_Tabs : constant Positive := 8;
35+
Tabs_Count : Natural := 0;
36+
37+
type Tabs_T is array (1 .. Max_Tabs) of Tab_T;
38+
39+
Tabs : Tabs_T;
40+
41+
procedure Load_Config_File (Filename : String; Verbose : Boolean := False);
42+
43+
Could_Not_Parse,
44+
Duplicate_Configuration,
45+
Incomplete_Configuration,
46+
Unknown_Configuration_Item : exception;
47+
48+
end Config;

src/keypadder.adb

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
-- SPDX-License-Identifier: GPL-3.0-or-later
2+
-- SPDX-FileCopyrightText: Copyright 2023 Stephen Merrony
3+
4+
with Ada.Command_Line; use Ada.Command_Line;
5+
with Ada.Directories;
6+
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
7+
with Ada.Text_IO; use Ada.Text_IO;
8+
9+
with AWS.Response;
10+
with AWS.Server;
11+
with AWS.Status;
12+
13+
with Config;
14+
15+
procedure Keypadder is
16+
17+
App_SemVer : constant String := "0.1.0"; -- TODO Update App_SemVer for each release
18+
19+
Arg_Ix : Natural := 1;
20+
Config_Arg : Unbounded_String := Null_Unbounded_String;
21+
Verbose : Boolean := True; -- FIXME debugging
22+
23+
WS : AWS.Server.HTTP;
24+
Do_Shutdown : Boolean := False;
25+
26+
function HW_CB (Request : AWS.Status.Data)
27+
return AWS.Response.Data
28+
is
29+
URI : constant String := AWS.Status.URI (Request);
30+
begin
31+
if URI = "/hello" then
32+
return AWS.Response.Build ("text/html", "<p>Hello world !");
33+
elsif URI = "/shutdown" then
34+
Do_Shutdown := True;
35+
return AWS.Response.Build ("text/html", "<p>Shutting down...");
36+
else
37+
return AWS.Response.Build ("text/html", "<p>Hum...");
38+
end if;
39+
end HW_CB;
40+
41+
begin
42+
43+
while Arg_Ix <= Argument_Count loop
44+
if Argument (Arg_Ix) = "-V" or else Argument (Arg_Ix) = "-version" then
45+
Ada.Text_IO.Put_Line ("keypadder version: " & App_SemVer);
46+
return;
47+
elsif Argument (Arg_Ix) = "-v" or else Argument (Arg_Ix) = "-verbose" then
48+
Verbose := True;
49+
elsif Argument (Arg_Ix) = "-h" or else Argument (Arg_Ix) = "-help "then
50+
Put_Line ("Usage of keypadder:");
51+
Put_Line (" --config=<config-file> Configuration file for keypadder (required)");
52+
Put_Line (" -h | -help Show this help");
53+
Put_Line (" -V | -version Show the version of keypadder and exit");
54+
Put_Line (" -v | -verbose Show lots of detail when running");
55+
return;
56+
elsif Argument (Arg_Ix)'Length > 9 and then Argument (Arg_Ix)(1 .. 9) = "--config=" then
57+
Config_Arg := To_Unbounded_String (Argument (Arg_Ix)(10 .. Argument (Arg_Ix)'Length));
58+
end if;
59+
Arg_Ix := Arg_Ix + 1;
60+
end loop;
61+
62+
if Config_Arg = Null_Unbounded_String then
63+
Put_Line ("ERROR: You must specify a configuration file. Use '-h' for help.");
64+
return;
65+
end if;
66+
67+
if not Ada.Directories.Exists (To_String (Config_Arg)) then
68+
Put_Line ("ERROR: Configuration file: " & To_String (Config_Arg) & " does not exist.");
69+
return;
70+
end if;
71+
72+
Config.Load_Config_File (To_String (Config_Arg), Verbose);
73+
74+
AWS.Server.Start (WS,
75+
Name => "Keypadder Server",
76+
Callback => HW_CB'Unrestricted_Access,
77+
Max_Connection => 2,
78+
Port => 9090);
79+
loop
80+
delay 10.0;
81+
exit when Do_Shutdown;
82+
end loop;
83+
AWS.Server.Shutdown (WS);
84+
end Keypadder;

0 commit comments

Comments
 (0)