Add initial prototype.
This commit is contained in:
154
.gitignore
vendored
Normal file
154
.gitignore
vendored
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
## Gnat build artifacts
|
||||||
|
#
|
||||||
|
*.o
|
||||||
|
*.ali
|
||||||
|
*-loc.xml
|
||||||
|
gnatinspect.db
|
||||||
|
*~
|
||||||
|
auto.cgpr
|
||||||
|
*.stderr
|
||||||
|
*.stdout
|
||||||
|
*.a
|
||||||
|
*.log
|
||||||
|
.clang-format
|
||||||
|
.clangd
|
||||||
|
.#*
|
||||||
|
*.deps
|
||||||
|
*.d
|
||||||
|
.travis.yml
|
||||||
|
|
||||||
|
## Build folders
|
||||||
|
#
|
||||||
|
build
|
||||||
|
**/dsa/x86_64-unknown-linux-gnu
|
||||||
|
bin
|
||||||
|
|
||||||
|
|
||||||
|
## Source
|
||||||
|
#
|
||||||
|
2-low/neural/source/attic
|
||||||
|
2-low/neural/source/attic2
|
||||||
|
2-low/neural/implement
|
||||||
|
2-low/neural/applet/test/learn_linear/velocity.net
|
||||||
|
|
||||||
|
3-mid/impact/contrib
|
||||||
|
3-mid/physics/implement/impact/*
|
||||||
|
3-mid/physics/implement/vox/*
|
||||||
|
#3-mid/physics/implement/box2d/contrib
|
||||||
|
|
||||||
|
4-high/gel/source/platform/sdl/attic
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Assets
|
||||||
|
#
|
||||||
|
#**/assets/opengl
|
||||||
|
#**/assets/gel
|
||||||
|
**/assets/attic
|
||||||
|
3-mid/opengl/applet/demo/models/render_hex_grid/document
|
||||||
|
3-mid/opengl/applet/demo/models/render_hex_grid/assets
|
||||||
|
|
||||||
|
|
||||||
|
## Binaries
|
||||||
|
#
|
||||||
|
box2d_HelloWorld
|
||||||
|
launch_box_rig_1_bone_demo
|
||||||
|
launch_diffuse_light
|
||||||
|
launch_simple_instant_events_demo
|
||||||
|
launch_simple_deferred_events_demo
|
||||||
|
launch_simple_chat_client
|
||||||
|
launch_simple_chat_registrar
|
||||||
|
launch_outline
|
||||||
|
launch_parse_box
|
||||||
|
launch_learn_linear
|
||||||
|
launch_pong
|
||||||
|
launch_core_test
|
||||||
|
launch_opengl_model
|
||||||
|
launch_large_terrain_demo
|
||||||
|
launch_math_testsuite
|
||||||
|
launch_many_boxes_demo
|
||||||
|
launch_model_scaling
|
||||||
|
launch_modeller_test
|
||||||
|
launch_mouse_selection
|
||||||
|
launch_render_arrows
|
||||||
|
launch_render_asteroids
|
||||||
|
launch_render_billboards
|
||||||
|
launch_render_boxes
|
||||||
|
launch_render_screenshot
|
||||||
|
launch_render_text
|
||||||
|
launch_two_cameras_demo
|
||||||
|
launch_egl_linkage_test
|
||||||
|
generate_gl_types_spec
|
||||||
|
launch_freetype_linkage_test
|
||||||
|
launch_hello_physics_interface_2d_demo
|
||||||
|
launch_hello_physics_interface_3d_demo
|
||||||
|
launch_drop_ball_on_box
|
||||||
|
launch_drop_box_on_box
|
||||||
|
launch_gel_fused
|
||||||
|
launch_hello_gel
|
||||||
|
launch_human_rig_demo
|
||||||
|
launch_chains_2d
|
||||||
|
launch_hinged_box
|
||||||
|
launch_human_model
|
||||||
|
launch_human_model_v1
|
||||||
|
launch_mixed_joints
|
||||||
|
launch_mixed_joints_2d
|
||||||
|
launch_mixed_shapes
|
||||||
|
launch_text_sprite_demo
|
||||||
|
launch_impact_hello_3d_demo
|
||||||
|
launch_camera_demo
|
||||||
|
launch_render_lighting
|
||||||
|
launch_render_capsules
|
||||||
|
launch_rig_demo
|
||||||
|
launch_crunch
|
||||||
|
launch_render_models
|
||||||
|
launch_simple_animation
|
||||||
|
launch_full_demo
|
||||||
|
launch_hello_physics_interface_demo
|
||||||
|
launch_test_engine
|
||||||
|
launch_strings_demo
|
||||||
|
launch_add_rid
|
||||||
|
launch_add_rid_sprite_test
|
||||||
|
launch_pong_tute
|
||||||
|
build_all_lace
|
||||||
|
|
||||||
|
test_environ_paths
|
||||||
|
test_environ_compression
|
||||||
|
test_text_replace
|
||||||
|
test_environ_general
|
||||||
|
HelloWorld*
|
||||||
|
5-all/applet/build_all/build_all
|
||||||
|
test_dice
|
||||||
|
launch_hexagon_test
|
||||||
|
launch_render_hex_grid
|
||||||
|
|
||||||
|
|
||||||
|
## Old Code
|
||||||
|
#
|
||||||
|
*-old
|
||||||
|
*-orig
|
||||||
|
old-events
|
||||||
|
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
#
|
||||||
|
*.ogv
|
||||||
|
*.project
|
||||||
|
opengl-series
|
||||||
|
attic
|
||||||
|
coding_style.txt
|
||||||
|
|
||||||
|
|
||||||
|
## Alire
|
||||||
|
#
|
||||||
|
obj/
|
||||||
|
lib/
|
||||||
|
alire/
|
||||||
|
config/
|
||||||
|
|
||||||
|
|
||||||
|
## Projects
|
||||||
|
#
|
||||||
|
2-low/neural/
|
||||||
|
3-mid/impact/
|
||||||
|
|
||||||
10
0-floor/lace_shared/alire.toml
Normal file
10
0-floor/lace_shared/alire.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
name = "lace_shared"
|
||||||
|
description = "Default settings for GPR files in the Lace project."
|
||||||
|
version = "0.1.1"
|
||||||
|
|
||||||
|
authors = ["Rod Kay"]
|
||||||
|
maintainers = ["Rod Kay <rodakay5@gmail.com>"]
|
||||||
|
maintainers-logins = ["charlie5"]
|
||||||
|
|
||||||
|
licenses = "ISC"
|
||||||
|
website = "https://github.com/charlie5/lace-alire"
|
||||||
3
0-floor/lace_shared/debug.pra
Normal file
3
0-floor/lace_shared/debug.pra
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pragma Initialize_Scalars;
|
||||||
|
-- pragma Normalize_Scalars; -- For all units!
|
||||||
|
|
||||||
167
0-floor/lace_shared/lace_shared.gpr
Normal file
167
0-floor/lace_shared/lace_shared.gpr
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
abstract
|
||||||
|
project Lace_shared
|
||||||
|
is
|
||||||
|
-- Scenario Variables
|
||||||
|
--
|
||||||
|
|
||||||
|
type Os_Type is
|
||||||
|
("Windows_NT", "Linux", "MacOSX");
|
||||||
|
lace_OS : Os_Type := external ("Lace_OS", "Linux");
|
||||||
|
|
||||||
|
type Restrictions_Type is
|
||||||
|
("xgc", "ravenscar");
|
||||||
|
lace_Restrictions : Restrictions_Type := external ("Lace_Restrictions", "xgc");
|
||||||
|
|
||||||
|
type Build_Mode_Type is
|
||||||
|
("debug", "fast", "small");
|
||||||
|
lace_Build_Mode : Build_Mode_Type := external ("Lace_Build_Mode", "debug");
|
||||||
|
|
||||||
|
|
||||||
|
-- Declare various options.
|
||||||
|
--
|
||||||
|
|
||||||
|
Binder_Options := ();
|
||||||
|
|
||||||
|
Style_Options := ("-gnatyk", -- Check casings: a:attribute, k:keywords, n:package Standard identifiers, p:pragma, r:identifier references.
|
||||||
|
"-gnatybfhi", -- Check b:no blanks at end of lines, f:no ff/vtabs, h: no htabs, i:if-then layout, u:no unnecessary blank lines.
|
||||||
|
"-gnatyO", -- Check that overriding subprograms are explicitly marked as such.
|
||||||
|
"-gnatye", -- Check that labels on end statements (ending subprograms), and on exit statements (exiting named loops), are present.
|
||||||
|
"-gnatyx"); -- Check x:no extra parens.
|
||||||
|
|
||||||
|
Compiler_Options := ("-gnat2022",
|
||||||
|
"-gnatwa",
|
||||||
|
"-fno-strict-aliasing")
|
||||||
|
& Style_Options;
|
||||||
|
|
||||||
|
Fast_Options := ("-O2",
|
||||||
|
"-gnatn",
|
||||||
|
"-gnatp",
|
||||||
|
"-funroll-loops",
|
||||||
|
"-fpeel-loops",
|
||||||
|
"-ftracer",
|
||||||
|
"-funswitch-loops",
|
||||||
|
"-fweb",
|
||||||
|
"-frename-registers");
|
||||||
|
|
||||||
|
Small_Options := ("-Os",
|
||||||
|
"-gnatp",
|
||||||
|
"-fno-inline",
|
||||||
|
"-march=i386",
|
||||||
|
"-ffunction-sections",
|
||||||
|
"-falign-jumps=0",
|
||||||
|
"-falign-loops=0",
|
||||||
|
"-falign-functions=0",
|
||||||
|
"-mpreferred-stack-boundary=2");
|
||||||
|
|
||||||
|
|
||||||
|
-- Modify options to cater for the build mode.
|
||||||
|
--
|
||||||
|
|
||||||
|
case lace_Build_Mode
|
||||||
|
is
|
||||||
|
when "debug" =>
|
||||||
|
Binder_Options := Binder_Options & "-Es";
|
||||||
|
Compiler_Options := Compiler_Options & "-O0"
|
||||||
|
& "-gnato"
|
||||||
|
& "-fstack-check"
|
||||||
|
& "-g";
|
||||||
|
case lace_OS
|
||||||
|
is
|
||||||
|
when "Linux" =>
|
||||||
|
Compiler_Options := Compiler_Options & "-gnatVa";
|
||||||
|
|
||||||
|
when "Windows_NT" =>
|
||||||
|
Compiler_Options := Compiler_Options & "-fno-inline"
|
||||||
|
& "-gnatVcdeimoprst";
|
||||||
|
-- & "-gnatVf" -- (2016) turned off floating point validity check, seems to give
|
||||||
|
-- false positives on a scalar product for collision detection
|
||||||
|
when "MacOSX" =>
|
||||||
|
null;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
when "fast" =>
|
||||||
|
case lace_OS
|
||||||
|
is
|
||||||
|
when "Linux" =>
|
||||||
|
Compiler_Options := Compiler_Options & Fast_Options
|
||||||
|
& "-fomit-frame-pointer";
|
||||||
|
when "Windows_NT" =>
|
||||||
|
Compiler_Options := Compiler_Options & Fast_Options
|
||||||
|
& "-fipa-cp-clone"
|
||||||
|
& "-fgcse-after-reload"
|
||||||
|
& "-ftree-vectorize"
|
||||||
|
& "-mfpmath=sse"
|
||||||
|
& "-msse3";
|
||||||
|
when "MacOSX" =>
|
||||||
|
null;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
when "small" =>
|
||||||
|
case lace_OS
|
||||||
|
is
|
||||||
|
when "Linux" =>
|
||||||
|
Compiler_Options := Compiler_Options & Small_Options
|
||||||
|
& "-fdata-sections";
|
||||||
|
when "Windows_NT" =>
|
||||||
|
Compiler_Options := Compiler_Options & Small_Options;
|
||||||
|
|
||||||
|
when "MacOSX" =>
|
||||||
|
null;
|
||||||
|
end case;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
|
||||||
|
-- Modify options to cater for the operating system.
|
||||||
|
--
|
||||||
|
|
||||||
|
case lace_OS
|
||||||
|
is
|
||||||
|
when "MacOSX" =>
|
||||||
|
Compiler_Options := Compiler_Options & "-gnatf"
|
||||||
|
& "-gnatE"
|
||||||
|
& "-gnatVcfimorst"
|
||||||
|
& "-gnatyhiknp";
|
||||||
|
when "Linux" =>
|
||||||
|
Binder_Options := Binder_Options & "-static";
|
||||||
|
|
||||||
|
when "Windows_NT" =>
|
||||||
|
null;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
|
||||||
|
-- Define the packages.
|
||||||
|
--
|
||||||
|
|
||||||
|
package Ide is
|
||||||
|
case lace_OS
|
||||||
|
is
|
||||||
|
when "Linux" => for Default_Switches ("adacontrol") use ("-Ftgnat_short");
|
||||||
|
when "Windows_NT" => for Default_Switches ("adacontrol") use ("-F", "gnat_short");
|
||||||
|
when "MacOSX" => for Default_Switches ("adacontrol") use ();
|
||||||
|
end case;
|
||||||
|
end Ide;
|
||||||
|
|
||||||
|
|
||||||
|
package Builder is
|
||||||
|
for Default_Switches ("ada") use ("-C", "-j0");
|
||||||
|
|
||||||
|
case lace_Build_Mode
|
||||||
|
is
|
||||||
|
when "debug" => for Global_Configuration_Pragmas use "debug.pra";
|
||||||
|
for Default_Switches ("ada") use ("-C", "-j0", "-gnat2022"); -- TODO: Create and use a Builder_Options variable ?
|
||||||
|
when "fast" => null;
|
||||||
|
when "small" => null;
|
||||||
|
end case;
|
||||||
|
end Builder;
|
||||||
|
|
||||||
|
|
||||||
|
package Compiler is
|
||||||
|
for Default_Switches ("ada") use Compiler_Options;
|
||||||
|
end Compiler;
|
||||||
|
|
||||||
|
|
||||||
|
package Binder is
|
||||||
|
for Default_Switches ("ada") use Binder_Options;
|
||||||
|
end Binder;
|
||||||
|
|
||||||
|
end Lace_shared;
|
||||||
15
1-base/lace/Overview
Normal file
15
1-base/lace/Overview
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
Lace ~ Overview
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
General:
|
||||||
|
|
||||||
|
- Contains a set of low level re-usable Ada components.
|
||||||
|
|
||||||
|
|
||||||
|
Contains:
|
||||||
|
|
||||||
|
- lace.Events : Provides a 'subject/oberver' 'event/response' facility.
|
||||||
|
- lace.Any : Provides an interface to allow heterogenous containers.
|
||||||
|
- lace.fast_Pool : Provides a generic which allows fast allocation/deallocation.
|
||||||
|
- lace.Text : Provides a DSA friendly set of text operations.
|
||||||
|
|
||||||
18
1-base/lace/alire.toml
Normal file
18
1-base/lace/alire.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
name = "lace"
|
||||||
|
description = "Contains a set of low level re-usable Ada components."
|
||||||
|
version = "0.1.1"
|
||||||
|
|
||||||
|
authors = ["Rod Kay"]
|
||||||
|
maintainers = ["Rod Kay <rodakay5@gmail.com>"]
|
||||||
|
maintainers-logins = ["charlie5"]
|
||||||
|
|
||||||
|
licenses = "ISC"
|
||||||
|
website = "https://github.com/charlie5/lace-alire"
|
||||||
|
tags = ["event", "response", "subject", "observer", "pool", "text"]
|
||||||
|
|
||||||
|
long-description = "\nContains:\n\n - lace.Events : Provides a 'subject/oberver' 'event/response' facility.\n - lace.Any : Provides an interface to allow heterogenous containers.\n - lace.fast_Pool : Provides a generic which allows fast allocation/deallocation.\n - lace.Text : Provides a DSA friendly set of text operations.\n\n"
|
||||||
|
|
||||||
|
project-files = ["library/lace.gpr"]
|
||||||
|
|
||||||
|
[[depends-on]]
|
||||||
|
lace_shared = "~0.1"
|
||||||
14
1-base/lace/applet/demo/event/distributed/builder.sh
Executable file
14
1-base/lace/applet/demo/event/distributed/builder.sh
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
export OS=Linux
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
|
||||||
|
rm -fr dsa
|
||||||
|
export Build_Mode=debug
|
||||||
|
po_gnatdist -P simple_chat.gpr simple_chat.dsa -cargs -g -largs -g
|
||||||
|
|
||||||
|
#rm -fr build
|
||||||
|
#rm -fr dsa
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
with
|
||||||
|
chat.Client.local,
|
||||||
|
|
||||||
|
lace.Event.utility,
|
||||||
|
|
||||||
|
ada.Characters.latin_1,
|
||||||
|
ada.command_Line,
|
||||||
|
ada.Text_IO,
|
||||||
|
ada.Exceptions;
|
||||||
|
|
||||||
|
procedure launch_simple_chat_Client
|
||||||
|
--
|
||||||
|
-- Starts a chat client.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
use ada.Text_IO;
|
||||||
|
begin
|
||||||
|
-- Usage
|
||||||
|
--
|
||||||
|
if ada.command_Line.argument_Count /= 1
|
||||||
|
then
|
||||||
|
put_Line ("Usage: $ ./launch_simple_chat_Client <nickname>");
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
declare
|
||||||
|
use chat.Client.local;
|
||||||
|
|
||||||
|
client_Name : constant String := ada.command_Line.Argument (1);
|
||||||
|
the_Client : chat.Client.local.item := to_Client (client_Name);
|
||||||
|
begin
|
||||||
|
the_Client.start;
|
||||||
|
end;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when E : others =>
|
||||||
|
lace.Event.utility.close;
|
||||||
|
|
||||||
|
new_Line;
|
||||||
|
put_Line ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||||
|
put_Line ("Unhandled exception, aborting. Please report the following to developer.");
|
||||||
|
put_Line ("________________________________________________________________________");
|
||||||
|
put_Line (ada.Exceptions.exception_Information (E));
|
||||||
|
put (ada.Characters.latin_1.ESC & "[1A"); -- Move cursor up.
|
||||||
|
put_Line ("________________________________________________________________________");
|
||||||
|
new_Line;
|
||||||
|
end launch_simple_chat_Client;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
with
|
||||||
|
chat.Registrar,
|
||||||
|
ada.Exceptions,
|
||||||
|
ada.Characters.latin_1,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
procedure launch_simple_chat_Registrar
|
||||||
|
--
|
||||||
|
-- Launches the chat registrar.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
use ada.Text_IO;
|
||||||
|
begin
|
||||||
|
loop
|
||||||
|
declare
|
||||||
|
Command : constant String := get_Line;
|
||||||
|
begin
|
||||||
|
exit when Command = "q";
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
put_Line ("Shutting down.");
|
||||||
|
chat.Registrar.shutdown;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when E : others =>
|
||||||
|
new_Line;
|
||||||
|
put_Line ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||||
|
put_Line ("Unhandled exception, aborting. Please report the following to developer.");
|
||||||
|
put_Line ("________________________________________________________________________");
|
||||||
|
put_Line (ada.Exceptions.exception_Information (E));
|
||||||
|
put (ada.Characters.latin_1.ESC & "[1A"); -- Move cursor up.
|
||||||
|
put_Line ("________________________________________________________________________");
|
||||||
|
new_Line;
|
||||||
|
end launch_simple_chat_Registrar;
|
||||||
70
1-base/lace/applet/demo/event/distributed/simple_chat.dsa
Normal file
70
1-base/lace/applet/demo/event/distributed/simple_chat.dsa
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
configuration simple_Chat is
|
||||||
|
|
||||||
|
|
||||||
|
pragma Starter (none);
|
||||||
|
--
|
||||||
|
-- Tell 'po_gnatdist' to not create any startup script or launcher.
|
||||||
|
-- We will launch our Server and Client partitions manually from a console.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Server
|
||||||
|
--
|
||||||
|
|
||||||
|
registrar_Partition : partition := (chat.Registrar);
|
||||||
|
--
|
||||||
|
-- Declare the Registrar partition and assign the Registrars 'remote call interface' package to this partition.
|
||||||
|
|
||||||
|
for registrar_Partition'Termination use Local_Termination;
|
||||||
|
|
||||||
|
|
||||||
|
procedure launch_simple_chat_Registrar is in registrar_Partition;
|
||||||
|
--
|
||||||
|
-- Tell po_gnatdist that the 'launch_simple_chat_Registrar' procedure is the the Servers 'main' subprogram or launcher.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Client
|
||||||
|
--
|
||||||
|
|
||||||
|
client_Partition : partition;
|
||||||
|
--
|
||||||
|
-- Declare the Client partition (which has no remote call interface package associated with it, so no 'initialisation' is required).
|
||||||
|
|
||||||
|
|
||||||
|
procedure launch_simple_chat_Client;
|
||||||
|
--
|
||||||
|
-- Declare the Clients 'main' subprogram or launcher.
|
||||||
|
|
||||||
|
|
||||||
|
for client_Partition'Main use launch_simple_chat_Client;
|
||||||
|
--
|
||||||
|
-- Tell po_gnatdist to assign the above declared 'launch_simple_chat_Client' procedure as the Clients 'main' subprogram or launcher.
|
||||||
|
|
||||||
|
|
||||||
|
for client_Partition'Termination use Local_Termination;
|
||||||
|
--
|
||||||
|
-- Tell po_Gnatdist that Clients may terminate locally (more on this later).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Channels
|
||||||
|
--
|
||||||
|
|
||||||
|
-- The zip filter works only on 32 bits machines, don't try it on Digital Unix/Alpha.
|
||||||
|
--
|
||||||
|
-- Channel_1 : Channel := (server_Partition, client_Partition);
|
||||||
|
-- for Channel_1'Filter use "zip";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Misc
|
||||||
|
--
|
||||||
|
|
||||||
|
for Partition'Directory use "bin";
|
||||||
|
--
|
||||||
|
-- Ask po_gnatdist to place the built Client and Server partition executables in the './bin' sub-folder.
|
||||||
|
|
||||||
|
end simple_Chat;
|
||||||
28
1-base/lace/applet/demo/event/distributed/simple_chat.gpr
Normal file
28
1-base/lace/applet/demo/event/distributed/simple_chat.gpr
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
with
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project simple_Chat
|
||||||
|
is
|
||||||
|
for Create_Missing_Dirs use "True";
|
||||||
|
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
-- for Main use ("launch_simple_chat_client.adb",
|
||||||
|
-- "launch_simple_chat_registrar.adb");
|
||||||
|
for Source_Dirs use (".",
|
||||||
|
"source");
|
||||||
|
|
||||||
|
package Dsa is
|
||||||
|
for Configuration_File use "simple_chat.dsa";
|
||||||
|
end Dsa;
|
||||||
|
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end simple_Chat;
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
with
|
||||||
|
chat.Registrar,
|
||||||
|
|
||||||
|
lace.Response,
|
||||||
|
lace.Observer,
|
||||||
|
lace.Event.utility,
|
||||||
|
|
||||||
|
system.RPC,
|
||||||
|
ada.Exceptions,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
package body chat.Client.local
|
||||||
|
is
|
||||||
|
-- Utility
|
||||||
|
--
|
||||||
|
function "+" (From : in unbounded_String) return String
|
||||||
|
renames to_String;
|
||||||
|
|
||||||
|
-- Responses
|
||||||
|
--
|
||||||
|
type Show is new lace.Response.item with null record;
|
||||||
|
|
||||||
|
-- Response is to display the chat message on the users console.
|
||||||
|
--
|
||||||
|
overriding
|
||||||
|
procedure respond (Self : in out Show; to_Event : in lace.Event.item'Class)
|
||||||
|
is
|
||||||
|
pragma Unreferenced (Self);
|
||||||
|
use ada.Text_IO;
|
||||||
|
the_Message : constant Message := Message (to_Event);
|
||||||
|
begin
|
||||||
|
put_Line (the_Message.Text (1 .. the_Message.Length));
|
||||||
|
end respond;
|
||||||
|
|
||||||
|
the_Response : aliased chat.Client.local.show;
|
||||||
|
|
||||||
|
|
||||||
|
-- Forge
|
||||||
|
--
|
||||||
|
function to_Client (Name : in String) return Item
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self : Item
|
||||||
|
do
|
||||||
|
Self.Name := to_unbounded_String (Name);
|
||||||
|
end return;
|
||||||
|
end to_Client;
|
||||||
|
|
||||||
|
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return to_String (Self.Name);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function as_Observer (Self : access Item) return lace.Observer.view
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self;
|
||||||
|
end as_Observer;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function as_Subject (Self : access Item) return lace.Subject.view
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self;
|
||||||
|
end as_Subject;
|
||||||
|
|
||||||
|
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure register_Client (Self : in out Item; other_Client : in Client.view)
|
||||||
|
is
|
||||||
|
use lace.Event.utility,
|
||||||
|
ada.Text_IO;
|
||||||
|
begin
|
||||||
|
lace.Event.utility.connect (the_Observer => Self'unchecked_Access,
|
||||||
|
to_Subject => other_Client.as_Subject,
|
||||||
|
with_Response => the_Response'Access,
|
||||||
|
to_Event_Kind => to_Kind (chat.Client.Message'Tag));
|
||||||
|
put_Line (other_Client.Name & " is here.");
|
||||||
|
end register_Client;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure deregister_Client (Self : in out Item; other_Client_as_Observer : in lace.Observer.view;
|
||||||
|
other_Client_Name : in String)
|
||||||
|
is
|
||||||
|
use lace.Event.utility,
|
||||||
|
ada.Text_IO;
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
Self.as_Subject.deregister (other_Client_as_Observer,
|
||||||
|
to_Kind (chat.Client.Message'Tag));
|
||||||
|
exception
|
||||||
|
when constraint_Error =>
|
||||||
|
raise unknown_Client with "Other client not known. Deregister is not required.";
|
||||||
|
end;
|
||||||
|
|
||||||
|
Self.as_Observer.rid (the_Response'unchecked_Access,
|
||||||
|
to_Kind (chat.Client.Message'Tag),
|
||||||
|
other_Client_Name);
|
||||||
|
|
||||||
|
put_Line (other_Client_Name & " leaves.");
|
||||||
|
end deregister_Client;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure Registrar_has_shutdown (Self : in out Item)
|
||||||
|
is
|
||||||
|
use ada.Text_IO;
|
||||||
|
begin
|
||||||
|
put_Line ("The Registrar has shutdown. Press <Enter> to exit.");
|
||||||
|
Self.Registrar_has_shutdown := True;
|
||||||
|
end Registrar_has_shutdown;
|
||||||
|
|
||||||
|
|
||||||
|
task check_Registrar_lives
|
||||||
|
is
|
||||||
|
entry start (Self : in chat.Client.local.view);
|
||||||
|
entry halt;
|
||||||
|
end check_Registrar_lives;
|
||||||
|
|
||||||
|
task body check_Registrar_lives
|
||||||
|
is
|
||||||
|
use ada.Text_IO;
|
||||||
|
Done : Boolean := False;
|
||||||
|
Self : chat.Client.local.view;
|
||||||
|
begin
|
||||||
|
loop
|
||||||
|
select
|
||||||
|
accept start (Self : in chat.Client.local.view)
|
||||||
|
do
|
||||||
|
check_Registrar_lives.Self := Self;
|
||||||
|
end start;
|
||||||
|
or
|
||||||
|
accept halt
|
||||||
|
do
|
||||||
|
Done := True;
|
||||||
|
end halt;
|
||||||
|
or
|
||||||
|
delay 15.0;
|
||||||
|
end select;
|
||||||
|
|
||||||
|
exit when Done;
|
||||||
|
|
||||||
|
begin
|
||||||
|
chat.Registrar.ping;
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error =>
|
||||||
|
put_Line ("The Registrar has died. Press <Enter> to exit.");
|
||||||
|
Self.Registrar_is_dead := True;
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when E : others =>
|
||||||
|
new_Line;
|
||||||
|
put_Line ("Error in check_Registrar_lives task.");
|
||||||
|
new_Line;
|
||||||
|
put_Line (ada.exceptions.exception_Information (E));
|
||||||
|
end check_Registrar_lives;
|
||||||
|
|
||||||
|
|
||||||
|
procedure start (Self : in out chat.Client.local.item)
|
||||||
|
is
|
||||||
|
use ada.Text_IO;
|
||||||
|
begin
|
||||||
|
-- Setup
|
||||||
|
--
|
||||||
|
begin
|
||||||
|
chat.Registrar.register (Self'unchecked_Access); -- Register our client with the registrar.
|
||||||
|
exception
|
||||||
|
when chat.Registrar.Name_already_used =>
|
||||||
|
put_Line (+Self.Name & " is already in use.");
|
||||||
|
check_Registrar_lives.halt;
|
||||||
|
return;
|
||||||
|
end;
|
||||||
|
|
||||||
|
lace.Event.utility.use_text_Logger ("events");
|
||||||
|
|
||||||
|
check_Registrar_lives.start (Self'unchecked_Access);
|
||||||
|
|
||||||
|
declare
|
||||||
|
Peers : constant chat.Client.views := chat.Registrar.all_Clients;
|
||||||
|
begin
|
||||||
|
for i in Peers'Range
|
||||||
|
loop
|
||||||
|
if Self'unchecked_Access /= Peers (i)
|
||||||
|
then
|
||||||
|
begin
|
||||||
|
Peers (i).register_Client (Self'unchecked_Access); -- Register our client with all other clients.
|
||||||
|
Self .register_Client (Peers (i)); -- Register all other clients with our client.
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error
|
||||||
|
| storage_Error =>
|
||||||
|
null; -- Peer (i) has died, so ignore it and do nothing.
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- Main loop
|
||||||
|
--
|
||||||
|
loop
|
||||||
|
declare
|
||||||
|
procedure broadcast (the_Text : in String)
|
||||||
|
is
|
||||||
|
the_Message : constant chat.Client.Message := (Length (Self.Name) + 2 + the_Text'Length,
|
||||||
|
+Self.Name & ": " & the_Text);
|
||||||
|
begin
|
||||||
|
Self.emit (the_Message);
|
||||||
|
end broadcast;
|
||||||
|
|
||||||
|
chat_Message : constant String := get_Line;
|
||||||
|
begin
|
||||||
|
exit
|
||||||
|
when chat_Message = "q"
|
||||||
|
or Self.Registrar_has_shutdown
|
||||||
|
or Self.Registrar_is_dead;
|
||||||
|
|
||||||
|
broadcast (chat_Message);
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
-- Shutdown
|
||||||
|
--
|
||||||
|
if not Self.Registrar_has_shutdown
|
||||||
|
and not Self.Registrar_is_dead
|
||||||
|
then
|
||||||
|
begin
|
||||||
|
chat.Registrar.deregister (Self'unchecked_Access);
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error =>
|
||||||
|
Self.Registrar_is_dead := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not Self.Registrar_is_dead
|
||||||
|
then
|
||||||
|
declare
|
||||||
|
Peers : constant chat.Client.views := chat.Registrar.all_Clients;
|
||||||
|
begin
|
||||||
|
for i in Peers'Range
|
||||||
|
loop
|
||||||
|
if Self'unchecked_Access /= Peers (i)
|
||||||
|
then
|
||||||
|
begin
|
||||||
|
Peers (i).deregister_Client ( Self'unchecked_Access, -- Deregister our client with every other client.
|
||||||
|
+Self.Name);
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error
|
||||||
|
| storage_Error =>
|
||||||
|
null; -- Peer is dead, so do nothing.
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
check_Registrar_lives.halt;
|
||||||
|
lace.Event.utility.close;
|
||||||
|
end start;
|
||||||
|
|
||||||
|
|
||||||
|
-- 'last_chance_Handler' is commented out to avoid multiple definitions
|
||||||
|
-- of link symbols in 'build_All' test procedure (Tier 5).
|
||||||
|
--
|
||||||
|
|
||||||
|
-- procedure last_chance_Handler (Msg : in system.Address;
|
||||||
|
-- Line : in Integer);
|
||||||
|
--
|
||||||
|
-- pragma Export (C, last_chance_Handler,
|
||||||
|
-- "__gnat_last_chance_handler");
|
||||||
|
--
|
||||||
|
-- procedure last_chance_Handler (Msg : in System.Address;
|
||||||
|
-- Line : in Integer)
|
||||||
|
-- is
|
||||||
|
-- pragma Unreferenced (Msg, Line);
|
||||||
|
-- use ada.Text_IO;
|
||||||
|
-- begin
|
||||||
|
-- put_Line ("The Registrar is not running.");
|
||||||
|
-- put_Line ("Press Ctrl-C to quit.");
|
||||||
|
-- check_Registrar_lives.halt;
|
||||||
|
-- delay Duration'Last;
|
||||||
|
-- end last_chance_Handler;
|
||||||
|
|
||||||
|
|
||||||
|
end chat.Client.local;
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
with
|
||||||
|
lace.Any;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
lace.make_Subject,
|
||||||
|
lace.make_Observer,
|
||||||
|
ada.Strings.unbounded;
|
||||||
|
|
||||||
|
package chat.Client.local
|
||||||
|
--
|
||||||
|
-- Provides a local client.
|
||||||
|
-- Names must be unique.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is limited new lace.Any.limited_item
|
||||||
|
and chat.Client .item with private;
|
||||||
|
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
|
||||||
|
-- Forge
|
||||||
|
--
|
||||||
|
function to_Client (Name : in String) return Item;
|
||||||
|
|
||||||
|
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return String;
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function as_Observer (Self : access Item) return lace.Observer.view;
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function as_Subject (Self : access Item) return lace.Subject.view;
|
||||||
|
|
||||||
|
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
procedure start (Self : in out chat.Client.local.item);
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure register_Client (Self : in out Item; other_Client : in Client.view);
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure deregister_Client (Self : in out Item; other_Client_as_Observer : in lace.Observer.view;
|
||||||
|
other_Client_Name : in String);
|
||||||
|
overriding
|
||||||
|
procedure Registrar_has_shutdown (Self : in out Item);
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
package Observer is new lace.make_Observer (lace.Any.limited_item);
|
||||||
|
package Subject is new lace.make_Subject (Observer .item);
|
||||||
|
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
type Item is limited new Subject .item
|
||||||
|
and chat.Client.item with
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
Registrar_has_shutdown : Boolean := False;
|
||||||
|
Registrar_is_dead : Boolean := False;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end chat.Client.local;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
with
|
||||||
|
lace.Event,
|
||||||
|
lace.Subject,
|
||||||
|
lace.Observer;
|
||||||
|
|
||||||
|
package chat.Client
|
||||||
|
--
|
||||||
|
-- Provides an interface to a chat client.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Types;
|
||||||
|
|
||||||
|
type Item is limited interface
|
||||||
|
and lace.Subject .item
|
||||||
|
and lace.Observer.item;
|
||||||
|
|
||||||
|
type View is access all Item'Class;
|
||||||
|
type Views is array (Positive range <>) of View;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Registrar_has_shutdown (Self : in out Item) is abstract;
|
||||||
|
procedure ping (Self : in Item) is null;
|
||||||
|
|
||||||
|
procedure register_Client (Self : in out Item; other_Client : in Client.view) is abstract;
|
||||||
|
|
||||||
|
procedure deregister_Client (Self : in out Item; other_Client_as_Observer : in lace.Observer.view;
|
||||||
|
other_Client_Name : in String) is abstract;
|
||||||
|
--
|
||||||
|
-- Raises unknown_Client exception when the other_Client is unknown.
|
||||||
|
|
||||||
|
|
||||||
|
function as_Observer (Self : access Item) return lace.Observer.view is abstract;
|
||||||
|
function as_Subject (Self : access Item) return lace.Subject .view is abstract;
|
||||||
|
|
||||||
|
|
||||||
|
type Message (Length : Natural) is new lace.Event.item with
|
||||||
|
record
|
||||||
|
Text : String (1..Length);
|
||||||
|
end record;
|
||||||
|
|
||||||
|
unknown_Client : exception;
|
||||||
|
|
||||||
|
end chat.Client;
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
with
|
||||||
|
lace.Observer,
|
||||||
|
|
||||||
|
system.RPC,
|
||||||
|
|
||||||
|
ada.Exceptions,
|
||||||
|
ada.Strings.unbounded,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
package body chat.Registrar
|
||||||
|
is
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
use type Client.view;
|
||||||
|
|
||||||
|
procedure last_chance_Handler (Msg : in system.Address;
|
||||||
|
Line : in Integer);
|
||||||
|
|
||||||
|
pragma Export (C, last_chance_Handler,
|
||||||
|
"__gnat_last_chance_handler");
|
||||||
|
|
||||||
|
procedure last_chance_Handler (Msg : in System.Address;
|
||||||
|
Line : in Integer)
|
||||||
|
is
|
||||||
|
pragma Unreferenced (Msg, Line);
|
||||||
|
use ada.Text_IO;
|
||||||
|
begin
|
||||||
|
put_Line ("Unable to start the Registrar.");
|
||||||
|
put_Line ("Please ensure the 'po_cos_naming' server is running.");
|
||||||
|
put_Line ("Press Ctrl-C to quit.");
|
||||||
|
|
||||||
|
delay Duration'Last;
|
||||||
|
end last_chance_Handler;
|
||||||
|
|
||||||
|
|
||||||
|
type client_Info is
|
||||||
|
record
|
||||||
|
View : Client.view;
|
||||||
|
Name : unbounded_String;
|
||||||
|
as_Observer : lace.Observer.view;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
type client_Info_array is array (Positive range <>) of client_Info;
|
||||||
|
|
||||||
|
max_Clients : constant := 5_000;
|
||||||
|
|
||||||
|
|
||||||
|
-- Protection against race conditions.
|
||||||
|
--
|
||||||
|
|
||||||
|
protected safe_Clients
|
||||||
|
is
|
||||||
|
procedure add (the_Client : in Client.view);
|
||||||
|
procedure rid (the_Client : in Client.view);
|
||||||
|
|
||||||
|
function all_client_Info return client_Info_array;
|
||||||
|
private
|
||||||
|
Clients : client_Info_array (1 .. max_Clients);
|
||||||
|
end safe_Clients;
|
||||||
|
|
||||||
|
|
||||||
|
protected body safe_Clients
|
||||||
|
is
|
||||||
|
procedure add (the_Client : in Client.view)
|
||||||
|
is
|
||||||
|
function "+" (From : in String) return unbounded_String
|
||||||
|
renames to_unbounded_String;
|
||||||
|
begin
|
||||||
|
for i in Clients'Range
|
||||||
|
loop
|
||||||
|
if Clients (i).View = null then
|
||||||
|
Clients (i).View := the_Client;
|
||||||
|
Clients (i).Name := +the_Client.Name;
|
||||||
|
Clients (i).as_Observer := the_Client.as_Observer;
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end add;
|
||||||
|
|
||||||
|
|
||||||
|
procedure rid (the_Client : in Client.view)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
for i in Clients'Range
|
||||||
|
loop
|
||||||
|
if Clients (i).View = the_Client then
|
||||||
|
Clients (i).View := null;
|
||||||
|
return;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
raise Program_Error with "Unknown client";
|
||||||
|
end rid;
|
||||||
|
|
||||||
|
|
||||||
|
function all_client_Info return client_Info_array
|
||||||
|
is
|
||||||
|
Count : Natural := 0;
|
||||||
|
Result : client_Info_array (1..max_Clients);
|
||||||
|
begin
|
||||||
|
for i in Clients'Range
|
||||||
|
loop
|
||||||
|
if Clients (i).View /= null
|
||||||
|
then
|
||||||
|
Count := Count + 1;
|
||||||
|
Result (Count) := Clients (i);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return Result (1..Count);
|
||||||
|
end all_client_Info;
|
||||||
|
|
||||||
|
end safe_Clients;
|
||||||
|
|
||||||
|
|
||||||
|
procedure register (the_Client : in Client.view)
|
||||||
|
is
|
||||||
|
Name : constant String := the_Client.Name;
|
||||||
|
all_Info : constant client_Info_array := safe_Clients.all_client_Info;
|
||||||
|
begin
|
||||||
|
for Each of all_Info
|
||||||
|
loop
|
||||||
|
if Each.Name = Name
|
||||||
|
then
|
||||||
|
raise Name_already_used;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
safe_Clients.add (the_Client);
|
||||||
|
end register;
|
||||||
|
|
||||||
|
|
||||||
|
procedure deregister (the_Client : in Client.view)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
safe_Clients.rid (the_Client);
|
||||||
|
end deregister;
|
||||||
|
|
||||||
|
|
||||||
|
function all_Clients return chat.Client.views
|
||||||
|
is
|
||||||
|
all_Info : constant client_Info_array := safe_Clients.all_client_Info;
|
||||||
|
Result : chat.Client.views (all_Info'Range);
|
||||||
|
begin
|
||||||
|
for i in Result'Range
|
||||||
|
loop
|
||||||
|
Result (i) := all_Info (i).View;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
end all_Clients;
|
||||||
|
|
||||||
|
|
||||||
|
task check_Client_lives
|
||||||
|
is
|
||||||
|
entry halt;
|
||||||
|
end check_Client_lives;
|
||||||
|
|
||||||
|
task body check_Client_lives
|
||||||
|
is
|
||||||
|
use ada.Text_IO;
|
||||||
|
Done : Boolean := False;
|
||||||
|
begin
|
||||||
|
loop
|
||||||
|
select
|
||||||
|
accept halt
|
||||||
|
do
|
||||||
|
Done := True;
|
||||||
|
end halt;
|
||||||
|
or
|
||||||
|
delay 15.0;
|
||||||
|
end select;
|
||||||
|
|
||||||
|
exit when Done;
|
||||||
|
|
||||||
|
declare
|
||||||
|
all_Info : constant client_Info_array := safe_Clients.all_client_Info;
|
||||||
|
|
||||||
|
Dead : client_Info_array (all_Info'Range);
|
||||||
|
dead_Count : Natural := 0;
|
||||||
|
|
||||||
|
function "+" (From : in unbounded_String) return String
|
||||||
|
renames to_String;
|
||||||
|
begin
|
||||||
|
for Each of all_Info
|
||||||
|
loop
|
||||||
|
begin
|
||||||
|
Each.View.ping;
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error
|
||||||
|
| storage_Error =>
|
||||||
|
put_Line (+Each.Name & " has died.");
|
||||||
|
deregister (Each.View);
|
||||||
|
|
||||||
|
dead_Count := dead_Count + 1;
|
||||||
|
Dead (dead_Count) := Each;
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
declare
|
||||||
|
all_Clients : constant Client.views := chat.Registrar.all_Clients;
|
||||||
|
begin
|
||||||
|
for Each of all_Clients
|
||||||
|
loop
|
||||||
|
for i in 1 .. dead_Count
|
||||||
|
loop
|
||||||
|
begin
|
||||||
|
put_Line ("Ridding " & (+Dead (i).Name) & " from " & Each.Name);
|
||||||
|
Each.deregister_Client ( Dead (i).as_Observer,
|
||||||
|
+Dead (i).Name);
|
||||||
|
exception
|
||||||
|
when chat.Client.unknown_Client =>
|
||||||
|
put_Line ("Deregister of " & (+Dead (i).Name) & " from " & Each.Name & " is not needed.");
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
end loop;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when E : others =>
|
||||||
|
new_Line;
|
||||||
|
put_Line ("Error in check_Client_lives task.");
|
||||||
|
new_Line;
|
||||||
|
put_Line (ada.Exceptions.exception_Information (E));
|
||||||
|
end check_Client_lives;
|
||||||
|
|
||||||
|
|
||||||
|
procedure shutdown
|
||||||
|
is
|
||||||
|
all_Clients : constant Client.views := chat.Registrar.all_Clients;
|
||||||
|
begin
|
||||||
|
for Each of all_Clients
|
||||||
|
loop
|
||||||
|
begin
|
||||||
|
Each.Registrar_has_shutdown;
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error =>
|
||||||
|
null; -- Client has died. No action needed since we are shutting down.
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
check_Client_lives.halt;
|
||||||
|
end shutdown;
|
||||||
|
|
||||||
|
|
||||||
|
procedure ping is null;
|
||||||
|
|
||||||
|
end chat.Registrar;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
with
|
||||||
|
chat.Client;
|
||||||
|
|
||||||
|
package chat.Registrar
|
||||||
|
--
|
||||||
|
-- A singleton providing the central chat registrar.
|
||||||
|
-- Limited to a maximum of 5_000 chat clients running at once.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Call_interface;
|
||||||
|
|
||||||
|
Name_already_used : exception;
|
||||||
|
|
||||||
|
procedure register (the_Client : in Client.view);
|
||||||
|
procedure deregister (the_Client : in Client.view);
|
||||||
|
|
||||||
|
function all_Clients return chat.Client.views;
|
||||||
|
|
||||||
|
procedure ping;
|
||||||
|
procedure shutdown;
|
||||||
|
|
||||||
|
end chat.Registrar;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package Chat
|
||||||
|
--
|
||||||
|
-- Provides a namespace for the chat family.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma Pure;
|
||||||
|
end Chat;
|
||||||
18
1-base/lace/applet/demo/event/distributed/test/lan/README
Normal file
18
1-base/lace/applet/demo/event/distributed/test/lan/README
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
Edit /etc/hosts to force usage of 127.0.0.1 by po_cos_naming.
|
||||||
|
|
||||||
|
For instance, given ...
|
||||||
|
|
||||||
|
/etc/hostname
|
||||||
|
foo
|
||||||
|
|
||||||
|
/etc/hosts
|
||||||
|
127.0.0.1 localhost
|
||||||
|
192.168.1.10 foo.mydomain.org foo
|
||||||
|
|
||||||
|
... change to ...
|
||||||
|
|
||||||
|
/etc/hosts
|
||||||
|
127.0.0.1 localhost
|
||||||
|
# 192.168.1.10 foo.mydomain.org foo
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# PolyORB configuration file for the chat Client_1.
|
||||||
|
|
||||||
|
[dsa]
|
||||||
|
|
||||||
|
name_service=corbaloc:iiop:1.2@127.0.0.1:5001/NameService/000000024fF0000000080000000
|
||||||
|
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5003
|
||||||
5
1-base/lace/applet/demo/event/distributed/test/lan/client_1/test.sh
Executable file
5
1-base/lace/applet/demo/event/distributed/test/lan/client_1/test.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
../../../bin/client_partition rod
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# PolyORB configuration file for the chat Client_2.
|
||||||
|
|
||||||
|
[dsa]
|
||||||
|
|
||||||
|
name_service=corbaloc:iiop:1.2@127.0.0.1:5001/NameService/000000024fF0000000080000000
|
||||||
|
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5004
|
||||||
5
1-base/lace/applet/demo/event/distributed/test/lan/client_2/test.sh
Executable file
5
1-base/lace/applet/demo/event/distributed/test/lan/client_2/test.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
../../../bin/client_partition ian
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# PolyORB configuration file for polyorb cos name server.
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5001
|
||||||
5
1-base/lace/applet/demo/event/distributed/test/lan/po_namer/test.sh
Executable file
5
1-base/lace/applet/demo/event/distributed/test/lan/po_namer/test.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
po_cos_naming
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# PolyORB configuration file for the chat Registrar server.
|
||||||
|
|
||||||
|
[dsa]
|
||||||
|
|
||||||
|
name_service=corbaloc:iiop:1.2@127.0.0.1:5001/NameService/000000024fF0000000080000000
|
||||||
|
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5002
|
||||||
5
1-base/lace/applet/demo/event/distributed/test/lan/registrar/test.sh
Executable file
5
1-base/lace/applet/demo/event/distributed/test/lan/registrar/test.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
../../../bin/registrar_partition
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# PolyORB configuration file for the chat Client_1.
|
||||||
|
|
||||||
|
[dsa]
|
||||||
|
|
||||||
|
name_service=corbaloc:iiop:1.2@127.0.0.1:5001/NameService/000000024fF0000000080000000
|
||||||
|
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5003
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# PolyORB configuration file for the chat Client_2.
|
||||||
|
|
||||||
|
[dsa]
|
||||||
|
|
||||||
|
name_service=corbaloc:iiop:1.2@127.0.0.1:5001/NameService/000000024fF0000000080000000
|
||||||
|
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5004
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# PolyORB configuration file for polyorb cos name server.
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5001
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# PolyORB configuration file for the chat Registrar server.
|
||||||
|
|
||||||
|
[dsa]
|
||||||
|
|
||||||
|
name_service=corbaloc:iiop:1.2@127.0.0.1:5001/NameService/000000024fF0000000080000000
|
||||||
|
|
||||||
|
|
||||||
|
[iiop]
|
||||||
|
|
||||||
|
## IIOP default port
|
||||||
|
#
|
||||||
|
polyorb.protocols.iiop.default_port=5002
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
with
|
||||||
|
"../lace_demo",
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project lace_simple_deferred_Events_Demo
|
||||||
|
is
|
||||||
|
type Restrictions is ("xgc", "ravenscar");
|
||||||
|
Restrictions : Restrictions := external ("restrictions");
|
||||||
|
|
||||||
|
for Create_Missing_Dirs use "True";
|
||||||
|
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Source_Dirs use (".");
|
||||||
|
for Main use ("launch_simple_deferred_events_demo.adb");
|
||||||
|
|
||||||
|
package Ide renames Lace_shared.Ide;
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end lace_simple_deferred_Events_Demo;
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
with
|
||||||
|
lace_demo_Events,
|
||||||
|
lace_demo_Keyboard,
|
||||||
|
|
||||||
|
lace.Observer.deferred,
|
||||||
|
lace.Subject .local,
|
||||||
|
|
||||||
|
lace.Response,
|
||||||
|
lace.Event.utility,
|
||||||
|
|
||||||
|
ada.Text_IO,
|
||||||
|
ada.Strings.unbounded,
|
||||||
|
ada.real_Time;
|
||||||
|
|
||||||
|
procedure launch_simple_deferred_events_Demo
|
||||||
|
--
|
||||||
|
-- A simple demonstration of the Lace deferred event system.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
use lace_demo_Events,
|
||||||
|
lace.Event,
|
||||||
|
lace.event.Utility,
|
||||||
|
Lace,
|
||||||
|
|
||||||
|
ada.text_IO,
|
||||||
|
ada.Strings.unbounded,
|
||||||
|
ada.real_Time;
|
||||||
|
|
||||||
|
-- Key Response
|
||||||
|
--
|
||||||
|
|
||||||
|
type key_Map_of_message is array (Character) of unbounded_String;
|
||||||
|
|
||||||
|
type key_Response is new Response.item with
|
||||||
|
record
|
||||||
|
key_to_message_Map : key_Map_of_message;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure respond (Self : in out key_Response; to_Event : in Event.item'Class)
|
||||||
|
is
|
||||||
|
the_Event : keyboard_Event renames keyboard_Event (to_Event);
|
||||||
|
begin
|
||||||
|
put_Line ( "Message is: " -- Our response is to display the message associated
|
||||||
|
& to_String (Self.key_to_message_Map (the_Event.Key))); -- with the keyboard event key on the console.
|
||||||
|
end respond;
|
||||||
|
|
||||||
|
|
||||||
|
--- Globals
|
||||||
|
--
|
||||||
|
|
||||||
|
the_Subject : Subject.local.view;
|
||||||
|
the_Observer : constant Observer.deferred.view := Observer.deferred.forge.new_Observer ("demo.Observer");
|
||||||
|
the_Response : aliased key_Response := (Response.item with
|
||||||
|
key_to_message_Map => ['a' => to_unbounded_String ("'a' was received from demo keyboard."),
|
||||||
|
'b' => to_unbounded_String ("'b' was received from demo keyboard."),
|
||||||
|
others => to_unbounded_String ("Unhandled key was received from demo keyboard.")]);
|
||||||
|
Now : ada.real_Time.Time := ada.real_Time.Clock;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Event.utility.use_text_Logger (log_filename => "events_demo"); -- Enable 'simple text file' event logging.
|
||||||
|
|
||||||
|
the_Subject := lace_demo_Keyboard.as_event_Subject; -- Get a reference to the keyboard as an event subject.
|
||||||
|
|
||||||
|
Event.utility.connect (the_observer => Observer.view (the_Observer), -- Setup out response to a keyboard event.
|
||||||
|
to_subject => Subject .view (the_Subject),
|
||||||
|
with_response => the_Response'unchecked_Access,
|
||||||
|
to_event_kind => to_Kind (keyboard_Event'Tag));
|
||||||
|
lace_demo_Keyboard.start;
|
||||||
|
|
||||||
|
for Each in 1 .. 5
|
||||||
|
loop -- Our main loop.
|
||||||
|
the_Observer.respond; -- Response to any queued events occur here.
|
||||||
|
|
||||||
|
Now := Now + to_time_Span (1.0);
|
||||||
|
delay until Now;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
lace_demo_Keyboard.stop;
|
||||||
|
Event.utility.close; -- Ensures event logging is closed (ie saved to log file).
|
||||||
|
end launch_simple_deferred_events_Demo;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
with
|
||||||
|
"../lace_demo",
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project lace_simple_instant_Events_Demo
|
||||||
|
is
|
||||||
|
type Restrictions is ("xgc", "ravenscar");
|
||||||
|
Restrictions : Restrictions := external ("restrictions");
|
||||||
|
|
||||||
|
for Create_Missing_Dirs use "True";
|
||||||
|
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Source_Dirs use (".");
|
||||||
|
for Main use ("launch_simple_instant_events_demo.adb");
|
||||||
|
|
||||||
|
package Ide renames Lace_shared.Ide;
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end lace_simple_instant_Events_Demo;
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
with
|
||||||
|
lace_demo_Events,
|
||||||
|
lace_demo_Keyboard,
|
||||||
|
|
||||||
|
lace.Observer.instant,
|
||||||
|
lace.Subject .local,
|
||||||
|
|
||||||
|
lace.Response,
|
||||||
|
lace.Event.utility,
|
||||||
|
|
||||||
|
ada.Text_IO,
|
||||||
|
ada.Strings.unbounded,
|
||||||
|
ada.real_Time;
|
||||||
|
|
||||||
|
procedure launch_simple_instant_events_Demo
|
||||||
|
--
|
||||||
|
-- A simple demonstration of the Lace event system.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
use lace_demo_Events,
|
||||||
|
Lace,
|
||||||
|
lace.Event,
|
||||||
|
lace.event.Utility,
|
||||||
|
|
||||||
|
ada.Text_IO,
|
||||||
|
ada.Strings.unbounded,
|
||||||
|
ada.real_Time;
|
||||||
|
|
||||||
|
-- key_Response
|
||||||
|
--
|
||||||
|
|
||||||
|
type key_Map_of_message is array (Character) of unbounded_String;
|
||||||
|
|
||||||
|
type key_Response is new Response.item with
|
||||||
|
record
|
||||||
|
key_to_message_Map : key_Map_of_message;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure respond (Self : in out key_Response; to_Event : in Event.item'Class)
|
||||||
|
is
|
||||||
|
the_Event : keyboard_Event renames keyboard_Event (to_Event);
|
||||||
|
begin
|
||||||
|
put_Line ( "Message is: " -- Our response is to display the message associated
|
||||||
|
& to_String (Self.key_to_message_Map (the_Event.Key))); -- with the keyboard event key on the console.
|
||||||
|
end respond;
|
||||||
|
|
||||||
|
|
||||||
|
-- Globals
|
||||||
|
--
|
||||||
|
|
||||||
|
the_Subject : Subject.local.view;
|
||||||
|
the_Observer : constant Observer.instant.view := Observer.instant.forge.new_Observer ("demo.Observer");
|
||||||
|
the_Response : aliased key_Response := (Response.item with
|
||||||
|
key_to_message_Map => ['a' => to_unbounded_String ("'a' was received from demo keyboard."),
|
||||||
|
'b' => to_unbounded_String ("'b' was received from demo keyboard."),
|
||||||
|
others => to_unbounded_String ("Unhandled key was received from demo keyboard.")]);
|
||||||
|
Now : ada.real_Time.Time := ada.real_Time.Clock;
|
||||||
|
|
||||||
|
begin
|
||||||
|
event.Utility.use_text_Logger (log_filename => "events_demo"); -- Enable simple text file event logging.
|
||||||
|
|
||||||
|
|
||||||
|
the_Subject := lace_demo_Keyboard.as_event_Subject; -- Get a reference to the keyboard as an event subject.
|
||||||
|
|
||||||
|
event.Utility.connect (the_observer => Observer.view (the_Observer), -- Setup our response to a keyboard event.
|
||||||
|
to_subject => Subject .view (the_Subject),
|
||||||
|
with_response => the_Response'unchecked_Access,
|
||||||
|
to_event_kind => to_Kind (keyboard_Event'Tag));
|
||||||
|
lace_demo_Keyboard.start;
|
||||||
|
|
||||||
|
for Each in 1 .. 5
|
||||||
|
loop -- Our main loop.
|
||||||
|
Now := Now + to_time_Span (1.0);
|
||||||
|
delay until Now;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
lace_demo_Keyboard.stop;
|
||||||
|
event.Utility.close; -- Ensure event logging is closed (ie saved to log file).
|
||||||
|
end launch_simple_instant_events_Demo;
|
||||||
24
1-base/lace/applet/demo/event/simple/lace_demo.gpr
Normal file
24
1-base/lace/applet/demo/event/simple/lace_demo.gpr
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
with
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project lace_Demo
|
||||||
|
is
|
||||||
|
type Restrictions is ("xgc", "ravenscar");
|
||||||
|
Restrictions : Restrictions := external ("restrictions");
|
||||||
|
|
||||||
|
for Create_Missing_Dirs use "True";
|
||||||
|
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Source_Dirs use (".");
|
||||||
|
|
||||||
|
package Ide renames Lace_shared.Ide;
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end lace_Demo;
|
||||||
16
1-base/lace/applet/demo/event/simple/lace_demo_events.ads
Normal file
16
1-base/lace/applet/demo/event/simple/lace_demo_events.ads
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
with
|
||||||
|
lace.Event;
|
||||||
|
|
||||||
|
package lace_demo_Events
|
||||||
|
--
|
||||||
|
-- Provides a simple derived lace 'event'.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Types;
|
||||||
|
|
||||||
|
type keyboard_Event is new lace.Event.item with
|
||||||
|
record
|
||||||
|
Key : Character;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace_demo_Events;
|
||||||
77
1-base/lace/applet/demo/event/simple/lace_demo_keyboard.adb
Normal file
77
1-base/lace/applet/demo/event/simple/lace_demo_keyboard.adb
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
with
|
||||||
|
lace_demo_Events,
|
||||||
|
ada.real_Time;
|
||||||
|
|
||||||
|
package body lace_demo_Keyboard
|
||||||
|
is
|
||||||
|
use lace_demo_Events,
|
||||||
|
Lace,
|
||||||
|
ada.real_Time;
|
||||||
|
|
||||||
|
--- Simulated Keyboard
|
||||||
|
--
|
||||||
|
|
||||||
|
the_event_Subject : constant Subject.local.view := Subject.local.forge.new_Subject ("demo.Subject");
|
||||||
|
|
||||||
|
|
||||||
|
task type simulated_Keyboard
|
||||||
|
is
|
||||||
|
entry start;
|
||||||
|
entry stop;
|
||||||
|
end simulated_Keyboard;
|
||||||
|
|
||||||
|
task body simulated_Keyboard
|
||||||
|
is
|
||||||
|
Count : Natural := 0;
|
||||||
|
Now : ada.real_Time.Time := ada.real_Time.Clock;
|
||||||
|
Done : Boolean := False;
|
||||||
|
begin
|
||||||
|
accept start;
|
||||||
|
|
||||||
|
loop
|
||||||
|
select
|
||||||
|
accept stop
|
||||||
|
do
|
||||||
|
Done := True;
|
||||||
|
end stop;
|
||||||
|
or
|
||||||
|
delay until Now;
|
||||||
|
end select;
|
||||||
|
|
||||||
|
exit when Done;
|
||||||
|
|
||||||
|
if Count mod 3 = 0
|
||||||
|
then
|
||||||
|
the_event_Subject.emit (the_Event => keyboard_Event'(key => 'a'));
|
||||||
|
else
|
||||||
|
the_event_Subject.emit (the_Event => keyboard_Event'(key => 'b'));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
Count := Count + 1;
|
||||||
|
Now := Now + to_time_Span (0.5);
|
||||||
|
end loop;
|
||||||
|
end simulated_Keyboard;
|
||||||
|
|
||||||
|
the_simulated_Keyboard : simulated_Keyboard;
|
||||||
|
|
||||||
|
|
||||||
|
function as_event_Subject return lace.Subject.local.view
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return the_event_Subject;
|
||||||
|
end as_event_Subject;
|
||||||
|
|
||||||
|
procedure start
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
the_simulated_Keyboard.start;
|
||||||
|
end start;
|
||||||
|
|
||||||
|
procedure stop
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
the_simulated_Keyboard.stop;
|
||||||
|
end stop;
|
||||||
|
|
||||||
|
end lace_demo_Keyboard;
|
||||||
|
|
||||||
14
1-base/lace/applet/demo/event/simple/lace_demo_keyboard.ads
Normal file
14
1-base/lace/applet/demo/event/simple/lace_demo_keyboard.ads
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
with
|
||||||
|
lace.Subject.local;
|
||||||
|
|
||||||
|
package lace_demo_Keyboard
|
||||||
|
--
|
||||||
|
-- Provides a simulated keyboard which periodically emits 'key' events.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
function as_event_Subject return lace.Subject.local.view;
|
||||||
|
|
||||||
|
procedure start;
|
||||||
|
procedure stop;
|
||||||
|
|
||||||
|
end lace_demo_Keyboard;
|
||||||
20
1-base/lace/applet/demo/strings/launch_strings_demo.adb
Normal file
20
1-base/lace/applet/demo/strings/launch_strings_demo.adb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
with
|
||||||
|
lace.Strings.bounded,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
procedure launch_strings_Demo
|
||||||
|
--
|
||||||
|
-- Displays a string message in a Pure unit.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
use ada.Text_IO;
|
||||||
|
|
||||||
|
package Text is new lace.Strings.Bounded.Generic_Bounded_Length (Max => 64);
|
||||||
|
use Text;
|
||||||
|
|
||||||
|
the_String : bounded_String := to_bounded_String ("Howdy ...");
|
||||||
|
|
||||||
|
begin
|
||||||
|
append (the_String, " doody !");
|
||||||
|
put_Line (to_String (the_String));
|
||||||
|
end launch_strings_Demo;
|
||||||
25
1-base/lace/applet/demo/strings/strings_demo.gpr
Normal file
25
1-base/lace/applet/demo/strings/strings_demo.gpr
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
with "lace";
|
||||||
|
|
||||||
|
project Strings_Demo
|
||||||
|
is
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Main use ("launch_strings_demo.adb");
|
||||||
|
|
||||||
|
package Builder is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Builder;
|
||||||
|
|
||||||
|
package Compiler is
|
||||||
|
for Default_Switches ("ada") use ("-gnato", "-fstack-check", "-g", "-gnata", "-gnat2022");
|
||||||
|
end Compiler;
|
||||||
|
|
||||||
|
package Binder is
|
||||||
|
for Default_Switches ("ada") use ("-E");
|
||||||
|
end Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end Strings_Demo;
|
||||||
74
1-base/lace/applet/test/dice/test_dice.adb
Normal file
74
1-base/lace/applet/test/dice/test_dice.adb
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
with
|
||||||
|
lace.Dice.d6,
|
||||||
|
lace.Dice.any,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
|
||||||
|
procedure test_Dice
|
||||||
|
is
|
||||||
|
procedure log (Message : in String) renames ada.Text_IO.put_Line;
|
||||||
|
|
||||||
|
test_Error : exception;
|
||||||
|
|
||||||
|
begin
|
||||||
|
log ("Begin Test");
|
||||||
|
|
||||||
|
|
||||||
|
-- d6x1
|
||||||
|
--
|
||||||
|
log ("");
|
||||||
|
log ("d6x1_less5 Roll:" & lace.Dice.d6.d6x1_less5.Roll'Image);
|
||||||
|
log ("d6x1_less4 Roll:" & lace.Dice.d6.d6x1_less4.Roll'Image);
|
||||||
|
log ("d6x1_less3 Roll:" & lace.Dice.d6.d6x1_less3.Roll'Image);
|
||||||
|
log ("d6x1_less2 Roll:" & lace.Dice.d6.d6x1_less2.Roll'Image);
|
||||||
|
log ("d6x1_less1 Roll:" & lace.Dice.d6.d6x1_less1.Roll'Image);
|
||||||
|
log ("d6x1 Roll:" & lace.Dice.d6.d6x1 .Roll'Image);
|
||||||
|
log ("d6x1_plus1 Roll:" & lace.Dice.d6.d6x1_plus1.Roll'Image);
|
||||||
|
log ("d6x1_plus2 Roll:" & lace.Dice.d6.d6x1_plus2.Roll'Image);
|
||||||
|
|
||||||
|
|
||||||
|
-- d6x2
|
||||||
|
--
|
||||||
|
log ("");
|
||||||
|
log ("d6x2_less1 Roll:" & lace.Dice.d6.d6x2_less1.Roll'Image);
|
||||||
|
log ("d6x2 Roll:" & lace.Dice.d6.d6x2 .Roll'Image);
|
||||||
|
log ("d6x2_plus1 Roll:" & lace.Dice.d6.d6x2_plus1.Roll'Image);
|
||||||
|
log ("d6x2_plus2 Roll:" & lace.Dice.d6.d6x2_plus2.Roll'Image);
|
||||||
|
|
||||||
|
|
||||||
|
-- any
|
||||||
|
--
|
||||||
|
declare
|
||||||
|
use lace.Dice,
|
||||||
|
lace.Dice.any;
|
||||||
|
|
||||||
|
d100 : constant lace.Dice.any.item := to_Dice (Sides => 100,
|
||||||
|
Rolls => 1,
|
||||||
|
Modifier => 0);
|
||||||
|
the_Roll : Natural;
|
||||||
|
one_Count : Natural := 0;
|
||||||
|
hundred_Count : Natural := 0;
|
||||||
|
begin
|
||||||
|
for i in 1 .. 1_000
|
||||||
|
loop
|
||||||
|
the_Roll := d100.Roll;
|
||||||
|
|
||||||
|
case the_Roll
|
||||||
|
is
|
||||||
|
when 0 => raise test_Error with "Roll was 0.";
|
||||||
|
when 1 => one_Count := one_Count + 1;
|
||||||
|
when 100 => hundred_Count := hundred_Count + 1;
|
||||||
|
when 101 => raise test_Error with "Roll was 101.";
|
||||||
|
when others => null;
|
||||||
|
end case;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
log ("");
|
||||||
|
log ("1 rolled" & one_Count'Image & " times.");
|
||||||
|
log ("100 rolled" & hundred_Count'Image & " times.");
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
log ("");
|
||||||
|
log ("End Test");
|
||||||
|
end test_Dice;
|
||||||
19
1-base/lace/applet/test/dice/test_dice.gpr
Normal file
19
1-base/lace/applet/test/dice/test_dice.gpr
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
with
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project test_Dice
|
||||||
|
is
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Main use ("test_dice.adb");
|
||||||
|
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end test_Dice;
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
with
|
||||||
|
lace.Environ,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
procedure test_Environ_compression
|
||||||
|
is
|
||||||
|
use lace.Environ,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
test_Error : exception;
|
||||||
|
digits_Text : constant String := "0123456789";
|
||||||
|
begin
|
||||||
|
put_Line ("Begin");
|
||||||
|
|
||||||
|
verify_Folder ("tmp");
|
||||||
|
goto_Folder ("tmp");
|
||||||
|
|
||||||
|
|
||||||
|
--- Compress single files.
|
||||||
|
--
|
||||||
|
save (digits_Text, "digits.txt-original");
|
||||||
|
copy_File ("digits.txt-original", "digits.txt");
|
||||||
|
|
||||||
|
for Each in compress_Format
|
||||||
|
loop
|
||||||
|
compress ("digits.txt", Each);
|
||||||
|
rid_File ("digits.txt");
|
||||||
|
decompress ("digits.txt" & format_Suffix (Each));
|
||||||
|
|
||||||
|
if load ("digits.txt") /= digits_Text
|
||||||
|
then
|
||||||
|
raise test_Error with "'" & load ("digits.txt") & "'";
|
||||||
|
end if;
|
||||||
|
|
||||||
|
rid_File ("digits.txt" & format_Suffix (Each));
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
|
||||||
|
--- Compress directories.
|
||||||
|
--
|
||||||
|
verify_Folder ("archive-original");
|
||||||
|
move_Files ("*", "archive-original");
|
||||||
|
copy_Folder ("archive-original", "archive");
|
||||||
|
|
||||||
|
for Each in folder_compress_Format
|
||||||
|
loop
|
||||||
|
compress ("archive", Each);
|
||||||
|
rid_Folder ("archive");
|
||||||
|
decompress ("archive" & format_Suffix (Each));
|
||||||
|
|
||||||
|
if load ("archive/digits.txt")
|
||||||
|
/= load ("archive-original/digits.txt")
|
||||||
|
then
|
||||||
|
raise test_Error with "'" & load ("archive/digits.txt") & "'";
|
||||||
|
end if;
|
||||||
|
|
||||||
|
rid_File ("archive" & format_Suffix (Each));
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
|
||||||
|
--- Tidy up
|
||||||
|
--
|
||||||
|
goto_Folder ("..");
|
||||||
|
rid_Folder ("tmp");
|
||||||
|
|
||||||
|
put_Line ("Success");
|
||||||
|
end test_Environ_compression;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
with
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project test_Environ_compression
|
||||||
|
is
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Main use ("test_environ_compression.adb");
|
||||||
|
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end test_Environ_compression;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
with
|
||||||
|
lace.Environ,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
procedure test_Environ_general
|
||||||
|
is
|
||||||
|
use lace.Environ,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
Error : exception;
|
||||||
|
begin
|
||||||
|
put_Line ("Begin");
|
||||||
|
|
||||||
|
-- Test GLOB expansion.
|
||||||
|
--
|
||||||
|
declare
|
||||||
|
Output : constant String := expand_GLOB ("data/*.txt");
|
||||||
|
begin
|
||||||
|
if Output /= "data/glob1.txt data/glob2.txt data/glob3.txt"
|
||||||
|
then
|
||||||
|
raise Error with "expand_GLOB fails: '" & Output & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
put_Line ("Success");
|
||||||
|
put_Line ("End");
|
||||||
|
end test_Environ_general;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
with
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project test_Environ_general
|
||||||
|
is
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Main use ("test_environ_general.adb");
|
||||||
|
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end test_Environ_general;
|
||||||
1
1-base/lace/applet/test/environ/paths/data/digits.txt
Normal file
1
1-base/lace/applet/test/environ/paths/data/digits.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0123456789
|
||||||
38
1-base/lace/applet/test/environ/paths/test_environ_paths.adb
Normal file
38
1-base/lace/applet/test/environ/paths/test_environ_paths.adb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
with
|
||||||
|
lace.Environ.Paths,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
procedure test_Environ_Paths
|
||||||
|
is
|
||||||
|
use lace.Environ.Paths,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
Error : exception;
|
||||||
|
begin
|
||||||
|
put_Line ("Begin");
|
||||||
|
|
||||||
|
-- Test load of an empty file.
|
||||||
|
--
|
||||||
|
declare
|
||||||
|
Output : constant String := to_File ("data/empty.txt").load;
|
||||||
|
begin
|
||||||
|
if Output /= ""
|
||||||
|
then
|
||||||
|
raise Error with "Loading an empty file fails: '" & Output & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
-- Test load of simple text.
|
||||||
|
--
|
||||||
|
declare
|
||||||
|
Output : constant String := to_File ("data/digits.txt").load;
|
||||||
|
begin
|
||||||
|
if Output /= "0123456789"
|
||||||
|
then
|
||||||
|
raise Error with "Loading a simple text file fails: '" & Output & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
put_Line ("Success");
|
||||||
|
put_Line ("End");
|
||||||
|
end test_Environ_Paths;
|
||||||
19
1-base/lace/applet/test/environ/paths/test_environ_paths.gpr
Normal file
19
1-base/lace/applet/test/environ/paths/test_environ_paths.gpr
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
with
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project test_Environ_Paths
|
||||||
|
is
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Main use ("test_environ_paths.adb");
|
||||||
|
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end test_Environ_Paths;
|
||||||
19
1-base/lace/applet/test/text/test_text.gpr
Normal file
19
1-base/lace/applet/test/text/test_text.gpr
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
with
|
||||||
|
"lace",
|
||||||
|
"lace_shared";
|
||||||
|
|
||||||
|
project test_Text
|
||||||
|
is
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Main use ("test_text_replace.adb");
|
||||||
|
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
package Linker is
|
||||||
|
for Default_Switches ("ada") use ("-g");
|
||||||
|
end Linker;
|
||||||
|
|
||||||
|
end test_Text;
|
||||||
221
1-base/lace/applet/test/text/test_text_replace.adb
Normal file
221
1-base/lace/applet/test/text/test_text_replace.adb
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
with
|
||||||
|
lace.Text.utility,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
procedure test_Text_replace
|
||||||
|
is
|
||||||
|
use lace.Text,
|
||||||
|
lace.Text.utility,
|
||||||
|
ada.Text_IO;
|
||||||
|
|
||||||
|
test_Error : exception;
|
||||||
|
begin
|
||||||
|
put_Line ("Begin Test");
|
||||||
|
new_Line;
|
||||||
|
|
||||||
|
-- Test 'replace' function.
|
||||||
|
--
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("<TOKEN>");
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "");
|
||||||
|
begin
|
||||||
|
if Final /= ""
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & (+Initial) & "' "
|
||||||
|
& "Final => '" & Final & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("<TOKEN>");
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "Linux");
|
||||||
|
begin
|
||||||
|
if Final /= "Linux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & (+Initial) & "' "
|
||||||
|
& "Final => '" & Final & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("123<TOKEN>456");
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "Linux");
|
||||||
|
begin
|
||||||
|
if Final /= "123Linux456"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & (+Initial) & "' "
|
||||||
|
& "Final => '" & Final & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("123<TOKEN>");
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "Linux");
|
||||||
|
begin
|
||||||
|
if Final /= "123Linux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & (+Initial) & "' "
|
||||||
|
& "Final => '" & Final & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("<TOKEN>456");
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "Linux");
|
||||||
|
begin
|
||||||
|
if Final /= "Linux456"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & (+Initial) & "' "
|
||||||
|
& "Final => '" & Final & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("<TOKEN>123<TOKEN>");
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "Linux");
|
||||||
|
begin
|
||||||
|
if Final /= "Linux123Linux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & (+Initial) & "' "
|
||||||
|
& "Final => '" & Final & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("<TOKEN><TOKEN>");
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "Linux");
|
||||||
|
begin
|
||||||
|
if Final /= "LinuxLinux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & (+Initial) & "' "
|
||||||
|
& "Final => '" & Final & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : aliased constant lace.Text.item := to_Text ("<TOKEN>", capacity => 64);
|
||||||
|
Final : constant String := +replace (Initial, "<TOKEN>", "Longish String") with Unreferenced;
|
||||||
|
begin
|
||||||
|
put_Line ("No capacity error raised, as expected.");
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
-- Test 'replace' procedure.
|
||||||
|
--
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "<TOKEN>";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "");
|
||||||
|
|
||||||
|
if +Text /= ""
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & Initial & "' "
|
||||||
|
& "Final => '" & (+Text) & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "<TOKEN>";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Linux");
|
||||||
|
|
||||||
|
if +Text /= "Linux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & Initial & "' "
|
||||||
|
& "Final => '" & (+Text) & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "123<TOKEN>456";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Linux");
|
||||||
|
|
||||||
|
if +Text /= "123Linux456"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & Initial & "' "
|
||||||
|
& "Final => '" & (+Text) & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "123<TOKEN>";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Linux");
|
||||||
|
|
||||||
|
if +Text /= "123Linux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & Initial & "' "
|
||||||
|
& "Final => '" & (+Text) & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "<TOKEN>456";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Linux");
|
||||||
|
|
||||||
|
if +Text /= "Linux456"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & Initial & "' "
|
||||||
|
& "Final => '" & (+Text) & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "<TOKEN>123<TOKEN>";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Linux");
|
||||||
|
|
||||||
|
if +Text /= "Linux123Linux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & Initial & "' "
|
||||||
|
& "Final => '" & (+Text) & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "<TOKEN><TOKEN>";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Linux");
|
||||||
|
|
||||||
|
if +Text /= "LinuxLinux"
|
||||||
|
then
|
||||||
|
raise test_Error with "replace fails: Initial => '" & Initial & "' "
|
||||||
|
& "Final => '" & (+Text) & "'";
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "<TOKEN>";
|
||||||
|
Text : lace.Text.item := to_Text (Initial);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Longish String");
|
||||||
|
|
||||||
|
exception
|
||||||
|
when lace.Text.Error =>
|
||||||
|
put_Line ("Capacity error raised, as expected.");
|
||||||
|
end;
|
||||||
|
|
||||||
|
declare
|
||||||
|
Initial : constant String := "<TOKEN>";
|
||||||
|
Text : lace.Text.item := to_Text (Initial, capacity => 64);
|
||||||
|
begin
|
||||||
|
replace (Text, "<TOKEN>", "Longish String");
|
||||||
|
put_Line ("No capacity error raised, as expected.");
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
new_Line;
|
||||||
|
put_Line ("Success");
|
||||||
|
put_Line ("End Test");
|
||||||
|
end test_Text_replace;
|
||||||
15
1-base/lace/document/events/Overview
Normal file
15
1-base/lace/document/events/Overview
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
'Lace ~ Events' Overview
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- Provides an event mechansism for event-driven architectures.
|
||||||
|
- Contains Subject, Observer, Event and Response abstractions.
|
||||||
|
- Supports DSA.
|
||||||
|
- See http://en.wikipedia.org/wiki/Event-driven_architecture
|
||||||
|
- http://en.wikipedia.org/wiki/Event-driven_programming
|
||||||
|
|
||||||
|
|
||||||
|
- Requirements: 'lace/document/events/requirements'
|
||||||
|
- Diagram: 'lace/document/events/events.png'
|
||||||
|
- Code: 'lace/source/events'
|
||||||
|
- Demo: 'lace/applet/demo/simple'
|
||||||
|
|
||||||
BIN
1-base/lace/document/events/events.dia
Normal file
BIN
1-base/lace/document/events/events.dia
Normal file
Binary file not shown.
BIN
1-base/lace/document/events/events.png
Normal file
BIN
1-base/lace/document/events/events.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
38
1-base/lace/document/events/requirements
Normal file
38
1-base/lace/document/events/requirements
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
'Lace ~ Event'
|
||||||
|
System Requirements
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
Overview
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
- Allow applet entities to communicate and operate by means of 'event/response' and 'subject/observer' objects.
|
||||||
|
- Subjects and Observers may be remotely distributed.
|
||||||
|
- Both lossy (unguaranteed) and lossless (guaranteed) event communication must be catered for.
|
||||||
|
|
||||||
|
|
||||||
|
Objects
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Events:
|
||||||
|
|
||||||
|
- Varied event kinds are required.
|
||||||
|
- Each variant may contain specific data related to the nature of the event.
|
||||||
|
|
||||||
|
Responses:
|
||||||
|
|
||||||
|
- Varied Response kinds are required.
|
||||||
|
- Each variant may contain specific data useful for performing the response.
|
||||||
|
- Each Response may perform a unique program operation.
|
||||||
|
|
||||||
|
Subjects:
|
||||||
|
|
||||||
|
- Allows an Observer to register interest in an Event of a specific kind.
|
||||||
|
- Must be able to emit an Event.
|
||||||
|
- Must notify all Observers (registered for the Event kind) when an Event is emitted.
|
||||||
|
|
||||||
|
Observers:
|
||||||
|
|
||||||
|
- Able to be configured with a Response to a specific Event (from a specific Subject).
|
||||||
|
- When notified of an Event, the configured response is performed.
|
||||||
|
- Must be able to respond to events in a task-safe fashion.
|
||||||
73
1-base/lace/document/events/tasking
Normal file
73
1-base/lace/document/events/tasking
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Event Responses and Tasking
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Default:
|
||||||
|
|
||||||
|
- Responses occur immediately after an event is emitted.
|
||||||
|
- Responses are performed by the task which asks a Subject to emit an event.
|
||||||
|
|
||||||
|
|
||||||
|
Deferred:
|
||||||
|
|
||||||
|
- In some cases, it may be desirable to be able to defer responses so as to free the emitting task from
|
||||||
|
the burden of performing lengthy responses.
|
||||||
|
- Such deferred responses would then be performed by another (possibly dedicated) task.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
Typical Cases
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- Note: '...' below signifies continued processing.
|
||||||
|
|
||||||
|
|
||||||
|
Single Task
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
Immediate Response
|
||||||
|
|
||||||
|
- Task asks Subject to emit an event.
|
||||||
|
- Task performs the Observer response immediately.
|
||||||
|
- ...
|
||||||
|
|
||||||
|
|
||||||
|
Deferred Response
|
||||||
|
|
||||||
|
- Task asks the Subject to emit an event.
|
||||||
|
- Task adds the event to the Observer queue.
|
||||||
|
- ...
|
||||||
|
- Task asks the Observer to perform the response.
|
||||||
|
- ...
|
||||||
|
|
||||||
|
|
||||||
|
- For a single task application, the default 'immediate response' method should be sufficent for most cases.
|
||||||
|
- The 'deferred response' method may be of use should control over the order in which responses occur be required.
|
||||||
|
- No concurrency protection is required when performing responses.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Multi Task
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
Immediate Response
|
||||||
|
|
||||||
|
- Task 1 asks Subject to emit an event.
|
||||||
|
- Task 1 performs the Observer response immediately.
|
||||||
|
- ...
|
||||||
|
|
||||||
|
|
||||||
|
Deferred Response
|
||||||
|
|
||||||
|
- Task 1 asks the Subject to emit an event.
|
||||||
|
- Task 1 adds the event to the Observer queue.
|
||||||
|
- ...
|
||||||
|
|
||||||
|
- Task 2 asks the Observer to perform response for each queued event.
|
||||||
|
- ...
|
||||||
|
|
||||||
|
|
||||||
|
- For a multi task application, care must be taken to ensure that response actions are task safe.
|
||||||
|
- Using the 'deferred' method may simplify (or eliminate) concurrency protection issues. (tbd: add examples)
|
||||||
|
|
||||||
38
1-base/lace/library/lace.gpr
Normal file
38
1-base/lace/library/lace.gpr
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
with
|
||||||
|
-- "florist",
|
||||||
|
"lace_shared";
|
||||||
|
-- "ashell";
|
||||||
|
|
||||||
|
|
||||||
|
--library
|
||||||
|
project Lace
|
||||||
|
is
|
||||||
|
type Restrictions is ("xgc", "ravenscar");
|
||||||
|
the_Restrictions : Restrictions := external ("restrictions", "xgc");
|
||||||
|
|
||||||
|
for Create_Missing_Dirs use "True";
|
||||||
|
|
||||||
|
for Object_Dir use "build";
|
||||||
|
for Exec_Dir use ".";
|
||||||
|
for Library_Dir use "lib";
|
||||||
|
for Library_Ali_Dir use "objects";
|
||||||
|
-- for Library_Name use "Lace";
|
||||||
|
|
||||||
|
for Source_Dirs use ("../source",
|
||||||
|
"../source/containers",
|
||||||
|
-- "../source/environ",
|
||||||
|
"../source/dice",
|
||||||
|
"../source/events",
|
||||||
|
"../source/events/concrete",
|
||||||
|
"../source/events/interface",
|
||||||
|
"../source/events/mixin",
|
||||||
|
"../source/events/mixin/" & external ("restrictions", "xgc"),
|
||||||
|
"../source/events/utility",
|
||||||
|
"../source/strings",
|
||||||
|
"../source/text");
|
||||||
|
|
||||||
|
package Builder renames Lace_shared.Builder;
|
||||||
|
package Compiler renames Lace_shared.Compiler;
|
||||||
|
package Binder renames Lace_shared.Binder;
|
||||||
|
|
||||||
|
end Lace;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
with
|
||||||
|
ada.Numerics.discrete_Random;
|
||||||
|
|
||||||
|
|
||||||
|
procedure lace.Containers.shuffle_Vector (the_Vector : in out vectors.Vector)
|
||||||
|
is
|
||||||
|
use type vectors.Index_type;
|
||||||
|
begin
|
||||||
|
for i in reverse 2 .. vectors.Index_type (the_Vector.Length) -- Start from 2, since swapping the
|
||||||
|
loop -- first element with itself is useless.
|
||||||
|
declare
|
||||||
|
subtype Index is vectors.Index_type range vectors.Index_type'First
|
||||||
|
.. vectors.Index_type'First + i - 1;
|
||||||
|
|
||||||
|
package random_Index is new ada.Numerics.discrete_Random (Index);
|
||||||
|
use random_Index;
|
||||||
|
|
||||||
|
the_Generator : random_Index.Generator;
|
||||||
|
begin
|
||||||
|
the_Vector.swap (Random (the_Generator),
|
||||||
|
Index'Last);
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
end lace.Containers.shuffle_Vector;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
with
|
||||||
|
ada.Containers.Vectors;
|
||||||
|
|
||||||
|
|
||||||
|
generic
|
||||||
|
with package Vectors is new ada.Containers.Vectors (<>);
|
||||||
|
|
||||||
|
procedure lace.Containers.shuffle_Vector (the_Vector : in out vectors.Vector);
|
||||||
12
1-base/lace/source/containers/lace-containers.ads
Normal file
12
1-base/lace/source/containers/lace-containers.ads
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
with
|
||||||
|
ada.Containers;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Containers
|
||||||
|
is
|
||||||
|
pragma Pure;
|
||||||
|
|
||||||
|
subtype Hash_Type is ada.Containers.Hash_type;
|
||||||
|
subtype Count_Type is ada.Containers.Count_type;
|
||||||
|
|
||||||
|
end lace.Containers;
|
||||||
69
1-base/lace/source/dice/lace-dice-any.adb
Normal file
69
1-base/lace/source/dice/lace-dice-any.adb
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
with
|
||||||
|
ada.Numerics.float_Random;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Dice.any
|
||||||
|
is
|
||||||
|
the_float_Generator : ada.Numerics.float_Random.Generator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
procedure Seed_is (Now : Integer)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
ada.Numerics.float_Random.reset (the_float_Generator,
|
||||||
|
Initiator => Now);
|
||||||
|
end Seed_is;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--------
|
||||||
|
-- Forge
|
||||||
|
--
|
||||||
|
function to_Dice (Sides : in Positive := 6;
|
||||||
|
Rolls : in Positive := 3;
|
||||||
|
Modifier : in Integer := 0) return Dice.any.item
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return (side_Count => Sides,
|
||||||
|
roll_Count => Rolls,
|
||||||
|
Modifier => Modifier);
|
||||||
|
end to_Dice;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function side_Count (Self : in Item) return Positive
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self.Side_Count;
|
||||||
|
end side_Count;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Roll (Self : in Item) return Natural
|
||||||
|
is
|
||||||
|
use ada.Numerics.float_Random;
|
||||||
|
|
||||||
|
the_Roll : Integer := 0;
|
||||||
|
begin
|
||||||
|
for Each in 1 .. Self.roll_Count
|
||||||
|
loop
|
||||||
|
the_Roll := the_Roll
|
||||||
|
+ Integer ( Random (the_float_Generator)
|
||||||
|
* Float (Self.side_Count)
|
||||||
|
+ 0.5);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return the_Roll + self.Modifier;
|
||||||
|
end Roll;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
ada.Numerics.float_Random.reset (the_float_Generator);
|
||||||
|
end lace.Dice.any;
|
||||||
44
1-base/lace/source/dice/lace-dice-any.ads
Normal file
44
1-base/lace/source/dice/lace-dice-any.ads
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package lace.Dice.any
|
||||||
|
--
|
||||||
|
-- provide a model of many sided dice.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is new Dice.item with private;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
procedure Seed_is (Now : Integer);
|
||||||
|
--
|
||||||
|
-- If the seed is not set, a random seed will be used.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--------
|
||||||
|
-- Forge
|
||||||
|
--
|
||||||
|
function to_Dice (Sides : in Positive := 6;
|
||||||
|
Rolls : in Positive := 3;
|
||||||
|
Modifier : in Integer := 0) return Dice.any.item;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
overriding
|
||||||
|
function side_Count (Self : in Item) return Positive;
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Roll (Self : in Item) return Natural;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
type Item is new Dice.item with
|
||||||
|
record
|
||||||
|
side_Count : Positive;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Dice.any;
|
||||||
|
|
||||||
70
1-base/lace/source/dice/lace-dice-d6.adb
Normal file
70
1-base/lace/source/dice/lace-dice-d6.adb
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
with
|
||||||
|
ada.Numerics.discrete_Random;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Dice.d6
|
||||||
|
is
|
||||||
|
|
||||||
|
subtype d6_Range is Positive range 1 .. 6;
|
||||||
|
package d6_Random is new ada.Numerics.discrete_Random (d6_Range);
|
||||||
|
|
||||||
|
the_d6_Generator : d6_Random.Generator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
procedure Seed_is (Now : Integer)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
d6_Random.reset (the_d6_Generator, Initiator => Now);
|
||||||
|
end Seed_is;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--------
|
||||||
|
-- Forge
|
||||||
|
--
|
||||||
|
|
||||||
|
function to_Dice (Rolls : in Positive := 3;
|
||||||
|
Modifier : in Integer := 0) return Dice.d6.item
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return (roll_count => Rolls,
|
||||||
|
modifier => Modifier);
|
||||||
|
end to_Dice;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function side_Count (Self : in Item) return Positive
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return 6;
|
||||||
|
end side_Count;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Roll (Self : in Item) return Natural
|
||||||
|
is
|
||||||
|
use d6_Random;
|
||||||
|
|
||||||
|
the_Roll : Integer := 0;
|
||||||
|
begin
|
||||||
|
for Each in 1 .. self.roll_Count loop
|
||||||
|
the_Roll := the_Roll + Random (the_d6_Generator);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return Natural'Max (the_Roll + self.Modifier,
|
||||||
|
0);
|
||||||
|
end Roll;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
d6_Random.reset (the_d6_Generator);
|
||||||
|
end lace.Dice.d6;
|
||||||
137
1-base/lace/source/dice/lace-dice-d6.ads
Normal file
137
1-base/lace/source/dice/lace-dice-d6.ads
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package lace.Dice.d6
|
||||||
|
--
|
||||||
|
-- Models 6 sided dice.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is new Dice.item with private;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
procedure Seed_is (Now : Integer);
|
||||||
|
--
|
||||||
|
-- If the seed is not set, a random seed will be used.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Forge
|
||||||
|
--
|
||||||
|
|
||||||
|
function to_Dice (Rolls : in Positive := 3;
|
||||||
|
Modifier : in Integer := 0) return Dice.d6.item;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function side_Count (Self : in Item) return Positive;
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Roll (Self : in Item) return Natural;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Stock Dice
|
||||||
|
--
|
||||||
|
|
||||||
|
d6x1_less5 : aliased constant d6.Item;
|
||||||
|
d6x1_less4 : aliased constant d6.Item;
|
||||||
|
d6x1_less3 : aliased constant d6.Item;
|
||||||
|
d6x1_less2 : aliased constant d6.Item;
|
||||||
|
d6x1_less1 : aliased constant d6.Item;
|
||||||
|
d6x1 : aliased constant d6.Item;
|
||||||
|
d6x1_plus1 : aliased constant d6.Item;
|
||||||
|
d6x1_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
d6x2_less1 : aliased constant d6.Item;
|
||||||
|
d6x2 : aliased constant d6.Item;
|
||||||
|
d6x2_plus1 : aliased constant d6.Item;
|
||||||
|
d6x2_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
d6x3_less1 : aliased constant d6.Item;
|
||||||
|
d6x3 : aliased constant d6.Item;
|
||||||
|
d6x3_plus1 : aliased constant d6.Item;
|
||||||
|
d6x3_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
d6x4_less1 : aliased constant d6.Item;
|
||||||
|
d6x4 : aliased constant d6.Item;
|
||||||
|
d6x4_plus1 : aliased constant d6.Item;
|
||||||
|
d6x4_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
d6x5_less1 : aliased constant d6.Item;
|
||||||
|
d6x5 : aliased constant d6.Item;
|
||||||
|
d6x5_plus1 : aliased constant d6.Item;
|
||||||
|
d6x5_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
d6x6_less1 : aliased constant d6.Item;
|
||||||
|
d6x6 : aliased constant d6.Item;
|
||||||
|
d6x6_plus1 : aliased constant d6.Item;
|
||||||
|
d6x6_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
d6x7_less1 : aliased constant d6.Item;
|
||||||
|
d6x7 : aliased constant d6.Item;
|
||||||
|
d6x7_plus1 : aliased constant d6.Item;
|
||||||
|
d6x7_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
d6x8_less1 : aliased constant d6.Item;
|
||||||
|
d6x8 : aliased constant d6.Item;
|
||||||
|
d6x8_plus1 : aliased constant d6.Item;
|
||||||
|
d6x8_plus2 : aliased constant d6.Item;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
type Item is new Dice.item with
|
||||||
|
record
|
||||||
|
null;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
|
||||||
|
d6x1_less5 : aliased constant d6.Item := (roll_count => 1, modifier => -5);
|
||||||
|
d6x1_less4 : aliased constant d6.Item := (roll_count => 1, modifier => -4);
|
||||||
|
d6x1_less3 : aliased constant d6.Item := (roll_count => 1, modifier => -3);
|
||||||
|
d6x1_less2 : aliased constant d6.Item := (roll_count => 1, modifier => -2);
|
||||||
|
d6x1_less1 : aliased constant d6.Item := (roll_count => 1, modifier => -1);
|
||||||
|
d6x1 : aliased constant d6.Item := (roll_count => 1, modifier => 0);
|
||||||
|
d6x1_plus1 : aliased constant d6.Item := (roll_count => 1, modifier => 1);
|
||||||
|
d6x1_plus2 : aliased constant d6.Item := (roll_count => 1, modifier => 2);
|
||||||
|
|
||||||
|
d6x2_less1 : aliased constant d6.Item := (roll_count => 2, modifier => -1);
|
||||||
|
d6x2 : aliased constant d6.Item := (roll_count => 2, modifier => 0);
|
||||||
|
d6x2_plus1 : aliased constant d6.Item := (roll_count => 2, modifier => 1);
|
||||||
|
d6x2_plus2 : aliased constant d6.Item := (roll_count => 2, modifier => 2);
|
||||||
|
|
||||||
|
d6x3_less1 : aliased constant d6.Item := (roll_count => 3, modifier => -1);
|
||||||
|
d6x3 : aliased constant d6.Item := (roll_count => 3, modifier => 0);
|
||||||
|
d6x3_plus1 : aliased constant d6.Item := (roll_count => 3, modifier => 1);
|
||||||
|
d6x3_plus2 : aliased constant d6.Item := (roll_count => 3, modifier => 2);
|
||||||
|
|
||||||
|
d6x4_less1 : aliased constant d6.Item := (roll_count => 4, modifier => -1);
|
||||||
|
d6x4 : aliased constant d6.Item := (roll_count => 4, modifier => 0);
|
||||||
|
d6x4_plus1 : aliased constant d6.Item := (roll_count => 4, modifier => 1);
|
||||||
|
d6x4_plus2 : aliased constant d6.Item := (roll_count => 4, modifier => 2);
|
||||||
|
|
||||||
|
d6x5_less1 : aliased constant d6.Item := (roll_count => 5, modifier => -1);
|
||||||
|
d6x5 : aliased constant d6.Item := (roll_count => 5, modifier => 0);
|
||||||
|
d6x5_plus1 : aliased constant d6.Item := (roll_count => 5, modifier => 1);
|
||||||
|
d6x5_plus2 : aliased constant d6.Item := (roll_count => 5, modifier => 2);
|
||||||
|
|
||||||
|
d6x6_less1 : aliased constant d6.Item := (roll_count => 6, modifier => -1);
|
||||||
|
d6x6 : aliased constant d6.Item := (roll_count => 6, modifier => 0);
|
||||||
|
d6x6_plus1 : aliased constant d6.Item := (roll_count => 6, modifier => 1);
|
||||||
|
d6x6_plus2 : aliased constant d6.Item := (roll_count => 6, modifier => 2);
|
||||||
|
|
||||||
|
d6x7_less1 : aliased constant d6.Item := (roll_count => 7, modifier => -1);
|
||||||
|
d6x7 : aliased constant d6.Item := (roll_count => 7, modifier => 0);
|
||||||
|
d6x7_plus1 : aliased constant d6.Item := (roll_count => 7, modifier => 1);
|
||||||
|
d6x7_plus2 : aliased constant d6.Item := (roll_count => 7, modifier => 2);
|
||||||
|
|
||||||
|
d6x8_less1 : aliased constant d6.Item := (roll_count => 8, modifier => -1);
|
||||||
|
d6x8 : aliased constant d6.Item := (roll_count => 8, modifier => 0);
|
||||||
|
d6x8_plus1 : aliased constant d6.Item := (roll_count => 8, modifier => 1);
|
||||||
|
d6x8_plus2 : aliased constant d6.Item := (roll_count => 8, modifier => 2);
|
||||||
|
|
||||||
|
end lace.Dice.d6;
|
||||||
|
|
||||||
65
1-base/lace/source/dice/lace-dice.adb
Normal file
65
1-base/lace/source/dice/lace-dice.adb
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Dice
|
||||||
|
is
|
||||||
|
|
||||||
|
|
||||||
|
function Image (Self : in Item'Class) return String
|
||||||
|
is
|
||||||
|
roll_count_Image : constant String := Integer'Image (self.roll_Count);
|
||||||
|
|
||||||
|
|
||||||
|
function side_count_Image return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
if Self.side_Count = 6 then
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
declare
|
||||||
|
the_Image : constant String := Integer'Image (Self.side_Count);
|
||||||
|
begin
|
||||||
|
return the_Image (the_Image'First + 1 .. the_Image'Last);
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end side_count_Image;
|
||||||
|
|
||||||
|
|
||||||
|
function modifier_Image return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
if self.Modifier = 0 then
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
declare
|
||||||
|
the_Image : String := integer'Image (self.Modifier);
|
||||||
|
begin
|
||||||
|
if self.Modifier > 0 then
|
||||||
|
the_Image (the_Image'First) := '+';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
return the_Image;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end modifier_Image;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
return roll_count_Image (roll_count_Image'First + 1 .. roll_count_Image'Last)
|
||||||
|
& "d"
|
||||||
|
& side_count_Image
|
||||||
|
& modifier_Image;
|
||||||
|
end Image;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Extent (Self : in Item'Class) return an_Extent
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return (min => self.roll_Count + self.Modifier,
|
||||||
|
max => self.roll_Count * self.side_Count + self.Modifier);
|
||||||
|
end Extent;
|
||||||
|
|
||||||
|
|
||||||
|
end lace.Dice;
|
||||||
|
|
||||||
34
1-base/lace/source/dice/lace-dice.ads
Normal file
34
1-base/lace/source/dice/lace-dice.ads
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package lace.Dice with Pure
|
||||||
|
--
|
||||||
|
-- Provides an abstract model of any sided dice.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is abstract tagged private;
|
||||||
|
|
||||||
|
|
||||||
|
type an_Extent is
|
||||||
|
record
|
||||||
|
Min, Max : Integer;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
function side_Count (Self : in Item) return Positive is abstract;
|
||||||
|
function Roll (Self : in Item) return Natural is abstract;
|
||||||
|
function Extent (Self : in Item'Class) return an_Extent;
|
||||||
|
function Image (Self : in Item'Class) return String;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
type Item is abstract tagged
|
||||||
|
record
|
||||||
|
roll_Count : Positive;
|
||||||
|
Modifier : Integer;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Dice;
|
||||||
|
|
||||||
98
1-base/lace/source/environ/lace-environ-os_commands.adb
Normal file
98
1-base/lace/source/environ/lace-environ-os_commands.adb
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
with
|
||||||
|
shell.Commands,
|
||||||
|
|
||||||
|
gnat.OS_Lib,
|
||||||
|
|
||||||
|
ada.Strings.fixed,
|
||||||
|
ada.Strings.Maps,
|
||||||
|
ada.Characters.latin_1,
|
||||||
|
ada.Exceptions;
|
||||||
|
|
||||||
|
package body lace.Environ.OS_Commands
|
||||||
|
is
|
||||||
|
use ada.Exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
function Path_to (Command : in String) return Paths.Folder
|
||||||
|
is
|
||||||
|
use Paths;
|
||||||
|
begin
|
||||||
|
return to_Folder (run_OS ("which " & Command));
|
||||||
|
end Path_to;
|
||||||
|
|
||||||
|
|
||||||
|
procedure run_OS (command_Line : in String;
|
||||||
|
Input : in String := "")
|
||||||
|
is
|
||||||
|
use Shell;
|
||||||
|
begin
|
||||||
|
Commands.run (command_Line, +Input);
|
||||||
|
exception
|
||||||
|
when E : Commands.command_Error =>
|
||||||
|
raise Error with Exception_Message (E);
|
||||||
|
end run_OS;
|
||||||
|
|
||||||
|
|
||||||
|
function run_OS (command_Line : in String;
|
||||||
|
Input : in String := "";
|
||||||
|
add_Errors : in Boolean := True) return String
|
||||||
|
is
|
||||||
|
use Shell,
|
||||||
|
Shell.Commands;
|
||||||
|
|
||||||
|
function trim_LF (Source : in String) return String
|
||||||
|
is
|
||||||
|
use ada.Strings.fixed,
|
||||||
|
ada.Strings.Maps,
|
||||||
|
ada.Characters;
|
||||||
|
|
||||||
|
LF_Set : constant Character_Set := to_Set (Latin_1.LF);
|
||||||
|
begin
|
||||||
|
return trim (Source, LF_Set, LF_Set);
|
||||||
|
end trim_LF;
|
||||||
|
|
||||||
|
Results : constant Command_Results := run (command_Line, +Input);
|
||||||
|
Output : constant String := +Output_of (Results);
|
||||||
|
begin
|
||||||
|
if add_Errors
|
||||||
|
then
|
||||||
|
return trim_LF (Output & (+Errors_of (Results)));
|
||||||
|
else
|
||||||
|
return trim_LF (Output);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when E : command_Error =>
|
||||||
|
raise Error with Exception_Message (E);
|
||||||
|
end run_OS;
|
||||||
|
|
||||||
|
|
||||||
|
function run_OS (command_Line : in String;
|
||||||
|
Input : in String := "") return Data
|
||||||
|
is
|
||||||
|
use Shell,
|
||||||
|
Shell.Commands;
|
||||||
|
the_Command : Command := Forge.to_Command (command_Line);
|
||||||
|
begin
|
||||||
|
return Output_of (run (The_Command, +Input));
|
||||||
|
exception
|
||||||
|
when E : command_Error =>
|
||||||
|
raise Error with Exception_Message (E);
|
||||||
|
end run_OS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Executable_on_Path (Executable : Paths.File) return Boolean
|
||||||
|
is
|
||||||
|
use Paths,
|
||||||
|
gnat.OS_Lib;
|
||||||
|
|
||||||
|
File_Path : String_Access := Locate_Exec_On_Path (+Executable);
|
||||||
|
Found : constant Boolean := File_Path /= null;
|
||||||
|
begin
|
||||||
|
free (File_Path);
|
||||||
|
return Found;
|
||||||
|
end Executable_on_Path;
|
||||||
|
|
||||||
|
|
||||||
|
end lace.Environ.OS_Commands;
|
||||||
33
1-base/lace/source/environ/lace-environ-os_commands.ads
Normal file
33
1-base/lace/source/environ/lace-environ-os_commands.ads
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
with
|
||||||
|
lace.Environ.Paths;
|
||||||
|
|
||||||
|
package lace.Environ.OS_Commands
|
||||||
|
--
|
||||||
|
-- Allows running of operating system commands.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
|
||||||
|
function Path_to (Command : in String) return Paths.Folder;
|
||||||
|
|
||||||
|
procedure run_OS (command_Line : in String;
|
||||||
|
Input : in String := "");
|
||||||
|
--
|
||||||
|
-- Discards any output. Error is raised when the command fails.
|
||||||
|
|
||||||
|
function run_OS (command_Line : in String;
|
||||||
|
Input : in String := "") return Data;
|
||||||
|
--
|
||||||
|
-- Returns any output. Error is raised when the command fails.
|
||||||
|
|
||||||
|
function run_OS (command_Line : in String;
|
||||||
|
Input : in String := "";
|
||||||
|
add_Errors : in Boolean := True) return String;
|
||||||
|
--
|
||||||
|
-- Returns any output. Error output is appended if add_Errors is true.
|
||||||
|
|
||||||
|
|
||||||
|
function Executable_on_Path (Executable : Paths.File) return Boolean;
|
||||||
|
--
|
||||||
|
-- Returns True if the Executable exists on the environment PATH variable.
|
||||||
|
|
||||||
|
end lace.Environ.OS_Commands;
|
||||||
1016
1-base/lace/source/environ/lace-environ-paths.adb
Normal file
1016
1-base/lace/source/environ/lace-environ-paths.adb
Normal file
File diff suppressed because it is too large
Load Diff
194
1-base/lace/source/environ/lace-environ-paths.ads
Normal file
194
1-base/lace/source/environ/lace-environ-paths.ads
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
with
|
||||||
|
ada.Calendar;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Strings.unbounded,
|
||||||
|
ada.Containers.indefinite_Vectors;
|
||||||
|
|
||||||
|
package lace.Environ.Paths
|
||||||
|
--
|
||||||
|
-- A singleton which models an operating system environment.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
|
||||||
|
function expand_GLOB (GLOB : in String) return String;
|
||||||
|
|
||||||
|
|
||||||
|
---------
|
||||||
|
--- Paths
|
||||||
|
--
|
||||||
|
type Path is abstract tagged private;
|
||||||
|
|
||||||
|
|
||||||
|
function to_String (Self : in Path'Class) return String;
|
||||||
|
function "+" (Self : in Path'Class) return String renames to_String;
|
||||||
|
|
||||||
|
procedure change_Mode (Self : in Path; To : in String);
|
||||||
|
procedure change_Owner (Self : in Path; To : in String);
|
||||||
|
procedure link (Self : in Path; To : in Path);
|
||||||
|
|
||||||
|
function Exists (Self : in Path) return Boolean;
|
||||||
|
function modify_Time (Self : in Path) return ada.Calendar.Time;
|
||||||
|
function Name (Self : in Path) return String;
|
||||||
|
function Simple (Self : in Path) return String;
|
||||||
|
|
||||||
|
function is_Folder (Self : in Path) return Boolean;
|
||||||
|
function is_File (Self : in Path) return Boolean;
|
||||||
|
function is_Special (Self : in Path) return Boolean;
|
||||||
|
|
||||||
|
function is_Absolute (Self : in Path) return Boolean;
|
||||||
|
function is_Relative (Self : in Path) return Boolean;
|
||||||
|
|
||||||
|
|
||||||
|
-----------
|
||||||
|
--- Folders
|
||||||
|
--
|
||||||
|
type Folder is new Path with private;
|
||||||
|
|
||||||
|
no_Folder : constant Folder;
|
||||||
|
|
||||||
|
function to_Folder (Name : in String) return Folder;
|
||||||
|
function "+" (Name : in String) return Folder renames to_Folder;
|
||||||
|
|
||||||
|
function "+" (Left : in Folder;
|
||||||
|
Right : in Folder) return Folder;
|
||||||
|
|
||||||
|
function current_Folder return Folder;
|
||||||
|
|
||||||
|
|
||||||
|
procedure go_to_Folder (Self : in Folder;
|
||||||
|
Lock : in Boolean := False); -- When true, blocks further folder changes until 'unlock_Folder' is called.
|
||||||
|
procedure unlock_Folder;
|
||||||
|
|
||||||
|
|
||||||
|
procedure rid_Folder (Self : in Folder);
|
||||||
|
procedure copy_Folder (Self : in Folder; To : in Folder);
|
||||||
|
procedure move_Folder (Self : in Folder; To : in Folder);
|
||||||
|
procedure rename_Folder (Self : in Folder; To : in Folder);
|
||||||
|
procedure ensure_Folder (Self : in Folder); -- Ensure that the folder exists.
|
||||||
|
|
||||||
|
function is_Empty (Self : in Folder) return Boolean;
|
||||||
|
function contents_Count (Self : in Folder; -- Does not include the "." and ".." folders.
|
||||||
|
Recurse : in Boolean := False) return Natural;
|
||||||
|
|
||||||
|
function Parent (Self : in Path'Class) return Folder; -- Returns 'no_Folder' if 'Self' has no parent.
|
||||||
|
function Relative (Self : in Folder; To : in Folder'Class) return Folder;
|
||||||
|
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
--- Folder Contexts
|
||||||
|
--
|
||||||
|
type folder_Context is limited private;
|
||||||
|
|
||||||
|
procedure push_Folder (Context : in out folder_Context;
|
||||||
|
goto_Folder : in Folder'Class);
|
||||||
|
--
|
||||||
|
-- Store the current folder and move to the 'goto_Folder'.
|
||||||
|
|
||||||
|
procedure pop_Folder (Context : in out folder_Context);
|
||||||
|
--
|
||||||
|
-- Return to the previously pushed folder.
|
||||||
|
|
||||||
|
procedure pop_All (Context : in out folder_Context);
|
||||||
|
--
|
||||||
|
-- Return to the initial current folder.
|
||||||
|
|
||||||
|
|
||||||
|
---------
|
||||||
|
--- Files
|
||||||
|
--
|
||||||
|
type File is new Path with private;
|
||||||
|
type File_Extension is new String;
|
||||||
|
|
||||||
|
function to_File (Name : in String) return File;
|
||||||
|
function "+" (Name : in String) return File renames to_File;
|
||||||
|
|
||||||
|
function "+" (Left : in Folder'Class;
|
||||||
|
Right : in File 'Class) return File;
|
||||||
|
|
||||||
|
function "+" (Left : in File'Class;
|
||||||
|
Right : in File_Extension) return File;
|
||||||
|
|
||||||
|
function Extension (Self : in File) return File_Extension;
|
||||||
|
|
||||||
|
procedure save (Self : in File;
|
||||||
|
Text : in String;
|
||||||
|
Binary : in Boolean := False);
|
||||||
|
|
||||||
|
procedure save (Self : in File;
|
||||||
|
Data : in environ.Data);
|
||||||
|
|
||||||
|
function load (Self : in File) return String;
|
||||||
|
function load (Self : in File) return Data;
|
||||||
|
|
||||||
|
procedure copy_File (Self : in File; To : in File);
|
||||||
|
procedure copy_Files (Named : in String; To : in Folder);
|
||||||
|
--
|
||||||
|
-- 'Named' can contain an asterix GLOB such as "*" or "*.txt".
|
||||||
|
|
||||||
|
procedure move_File (Self : in File; To : in File);
|
||||||
|
procedure move_Files (Named : in String; To : in Folder);
|
||||||
|
--
|
||||||
|
-- 'Named' can contain an asterix GLOB such as "*" or "*.txt".
|
||||||
|
|
||||||
|
procedure rid_File (Self : in File);
|
||||||
|
procedure rid_Files (Named : in String);
|
||||||
|
--
|
||||||
|
-- 'Named' can contain an asterix GLOB such as "*" or "*.txt".
|
||||||
|
|
||||||
|
procedure append (Self : in File; Text : in String);
|
||||||
|
procedure append_File (Self : in File; To : in File);
|
||||||
|
procedure touch (Self : in File);
|
||||||
|
|
||||||
|
function Relative (Self : in File; To : in Folder'Class) return File;
|
||||||
|
function rid_Extension (Self : in File) return File;
|
||||||
|
|
||||||
|
|
||||||
|
--- Compression
|
||||||
|
--
|
||||||
|
type compress_Format is (Tar, Tar_Bz2, Tar_Gz, Tar_Xz, Bz2, Gz, Xz);
|
||||||
|
subtype folder_compress_Format is compress_Format range Tar .. Tar_Xz;
|
||||||
|
|
||||||
|
type compress_Level is range 1 .. 9; -- Higher levels result in higher compression.
|
||||||
|
|
||||||
|
procedure compress (the_Path : in Path'Class;
|
||||||
|
the_Format : in compress_Format := Tar_Xz;
|
||||||
|
the_Level : in compress_Level := 6);
|
||||||
|
|
||||||
|
procedure decompress (Name : in File);
|
||||||
|
|
||||||
|
function format_Suffix (Format : in compress_Format) return String;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
type Path is abstract tagged
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
type Folder is new Path with null record;
|
||||||
|
type File is new Path with null record;
|
||||||
|
|
||||||
|
|
||||||
|
no_Folder : constant Folder := (Name => null_unbounded_String);
|
||||||
|
|
||||||
|
|
||||||
|
--- Folder Contexts
|
||||||
|
--
|
||||||
|
use ada.Containers;
|
||||||
|
|
||||||
|
package Folder_Vectors is new indefinite_Vectors (Positive, Folder);
|
||||||
|
subtype Folder_Vector is Folder_Vectors.Vector;
|
||||||
|
|
||||||
|
type folder_Context is limited
|
||||||
|
record
|
||||||
|
folder_Stack : Folder_Vector;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
|
||||||
|
end lace.Environ.Paths;
|
||||||
102
1-base/lace/source/environ/lace-environ-users.adb
Normal file
102
1-base/lace/source/environ/lace-environ-users.adb
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
with
|
||||||
|
lace.Environ.OS_Commands,
|
||||||
|
|
||||||
|
posix.user_Database,
|
||||||
|
posix.process_Identification;
|
||||||
|
|
||||||
|
package body lace.Environ.Users
|
||||||
|
is
|
||||||
|
function "+" (Source : in unbounded_String) return String
|
||||||
|
renames to_String;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function to_User (Name : in String) return User
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return (Name => to_unbounded_String (Name));
|
||||||
|
end to_User;
|
||||||
|
|
||||||
|
|
||||||
|
function Name (Self : in User) return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return to_String (Self.Name);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
|
||||||
|
procedure add_User (Self : in User;
|
||||||
|
Super : in Boolean := False)
|
||||||
|
is
|
||||||
|
use lace.Environ.OS_Commands;
|
||||||
|
begin
|
||||||
|
if Super
|
||||||
|
then
|
||||||
|
declare
|
||||||
|
Output : constant String := run_OS ("useradd " & (+Self.Name) & " -m -G sudo -G root");
|
||||||
|
begin
|
||||||
|
if Output /= ""
|
||||||
|
then
|
||||||
|
raise Error with Output;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
declare
|
||||||
|
Output : constant String := run_OS ("useradd " & (+Self.Name) & " -m");
|
||||||
|
begin
|
||||||
|
if Output /= ""
|
||||||
|
then
|
||||||
|
raise Error with Output;
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
end if;
|
||||||
|
end add_User;
|
||||||
|
|
||||||
|
|
||||||
|
procedure rid_User (Self : in User)
|
||||||
|
is
|
||||||
|
use lace.Environ.OS_Commands;
|
||||||
|
Output : constant String := run_OS ("userdel -r " & (+Self.Name));
|
||||||
|
begin
|
||||||
|
if Output /= ""
|
||||||
|
then
|
||||||
|
raise Error with Output;
|
||||||
|
end if;
|
||||||
|
end rid_User;
|
||||||
|
|
||||||
|
|
||||||
|
procedure switch_to (Self : in User)
|
||||||
|
is
|
||||||
|
use Posix,
|
||||||
|
posix.User_Database,
|
||||||
|
posix.Process_Identification;
|
||||||
|
|
||||||
|
User_in_DB : constant User_Database_Item := get_User_Database_Item (to_Posix_String (+Self.Name));
|
||||||
|
ID : constant User_ID := User_ID_of (User_in_DB);
|
||||||
|
begin
|
||||||
|
set_User_ID (ID);
|
||||||
|
end switch_to;
|
||||||
|
|
||||||
|
|
||||||
|
function current_User return User
|
||||||
|
is
|
||||||
|
use Posix,
|
||||||
|
posix.process_Identification;
|
||||||
|
begin
|
||||||
|
return to_User (to_String (get_Login_Name));
|
||||||
|
end current_User;
|
||||||
|
|
||||||
|
|
||||||
|
function home_Folder (Self : in User := current_User) return Paths.Folder
|
||||||
|
is
|
||||||
|
use Paths,
|
||||||
|
Posix,
|
||||||
|
posix.User_Database;
|
||||||
|
|
||||||
|
User_in_DB : constant User_Database_Item := get_User_Database_Item (to_Posix_String (+Self.Name));
|
||||||
|
begin
|
||||||
|
return to_Folder (to_String (initial_Directory_of (User_in_DB)));
|
||||||
|
end home_Folder;
|
||||||
|
|
||||||
|
|
||||||
|
end lace.Environ.Users;
|
||||||
38
1-base/lace/source/environ/lace-environ-users.ads
Normal file
38
1-base/lace/source/environ/lace-environ-users.ads
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
with
|
||||||
|
lace.Environ.Paths;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Strings.unbounded;
|
||||||
|
|
||||||
|
package lace.Environ.Users
|
||||||
|
--
|
||||||
|
-- Models operating system users.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type User is private;
|
||||||
|
|
||||||
|
function to_User (Name : in String) return User;
|
||||||
|
function "+" (Name : in String) return User renames to_User;
|
||||||
|
|
||||||
|
function Name (Self : in User) return String;
|
||||||
|
function current_User return User;
|
||||||
|
function home_Folder (Self : in User := current_User) return Paths.Folder;
|
||||||
|
|
||||||
|
procedure add_User (Self : in User;
|
||||||
|
Super : in Boolean := False);
|
||||||
|
procedure rid_User (Self : in User);
|
||||||
|
procedure switch_to (Self : in User);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
type User is
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Environ.Users;
|
||||||
40
1-base/lace/source/environ/lace-environ.adb
Normal file
40
1-base/lace/source/environ/lace-environ.adb
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package body lace.Environ
|
||||||
|
is
|
||||||
|
|
||||||
|
function to_octal_Mode (Permissions : in permission_Set) return String
|
||||||
|
is
|
||||||
|
function octal_Permissions (Bit_3, Bit_2, Bit_1 : in Boolean) return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
if Bit_3 then
|
||||||
|
if Bit_2 then
|
||||||
|
if Bit_1 then return "7";
|
||||||
|
else return "6";
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
if Bit_1 then return "5";
|
||||||
|
else return "4";
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
if Bit_2 then
|
||||||
|
if Bit_1 then return "3";
|
||||||
|
else return "2";
|
||||||
|
end if;
|
||||||
|
else
|
||||||
|
if Bit_1 then return "1";
|
||||||
|
else return "0";
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end octal_Permissions;
|
||||||
|
|
||||||
|
begin
|
||||||
|
return
|
||||||
|
octal_Permissions (Permissions (set_User_ID), Permissions (set_Group_ID), False)
|
||||||
|
& octal_Permissions (Permissions (owner_Read), Permissions (owner_Write), Permissions (owner_Execute))
|
||||||
|
& octal_Permissions (Permissions (group_Read), Permissions (group_Write), Permissions (group_Execute))
|
||||||
|
& octal_Permissions (Permissions (others_Read), Permissions (others_Write), Permissions (others_Execute));
|
||||||
|
end to_octal_Mode;
|
||||||
|
|
||||||
|
end lace.Environ;
|
||||||
17
1-base/lace/source/environ/lace-environ.ads
Normal file
17
1-base/lace/source/environ/lace-environ.ads
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
with
|
||||||
|
posix.Permissions,
|
||||||
|
ada.Streams;
|
||||||
|
|
||||||
|
package lace.Environ
|
||||||
|
--
|
||||||
|
-- Models an operating system environment.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
use posix.Permissions;
|
||||||
|
function to_octal_Mode (Permissions : in Permission_Set) return String;
|
||||||
|
|
||||||
|
subtype Data is ada.Streams.Stream_Element_Array;
|
||||||
|
|
||||||
|
Error : exception;
|
||||||
|
|
||||||
|
end lace.Environ;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package body lace.Observer.deferred
|
||||||
|
is
|
||||||
|
|
||||||
|
package body Forge
|
||||||
|
is
|
||||||
|
function to_Observer (Name : in Event.observer_Name) return Item
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self : constant Item := (Deferred.item
|
||||||
|
with name => to_unbounded_String (Name))
|
||||||
|
do
|
||||||
|
null;
|
||||||
|
end return;
|
||||||
|
end to_Observer;
|
||||||
|
|
||||||
|
|
||||||
|
function new_Observer (Name : in Event.observer_Name) return View
|
||||||
|
is
|
||||||
|
Self : constant View := new Item' (to_Observer (Name));
|
||||||
|
begin
|
||||||
|
return Self;
|
||||||
|
end new_Observer;
|
||||||
|
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return Event.observer_Name
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return to_String (Self.Name);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
end lace.Observer.deferred;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
with
|
||||||
|
lace.make_Observer.deferred,
|
||||||
|
lace.Any;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Strings.unbounded;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Observer.deferred
|
||||||
|
--
|
||||||
|
-- Provides a concrete deferred event observer.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is limited new Any.limited_item
|
||||||
|
and Observer .item with private;
|
||||||
|
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
|
||||||
|
package Forge
|
||||||
|
is
|
||||||
|
function to_Observer (Name : in Event.observer_Name) return Item;
|
||||||
|
function new_Observer (Name : in Event.observer_Name) return View;
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return Event.observer_Name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
package Observer is new lace.make_Observer (Any.limited_item);
|
||||||
|
package Deferred is new Observer.deferred (Observer.item);
|
||||||
|
|
||||||
|
type Item is limited new Deferred.item with
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Observer.deferred;
|
||||||
23
1-base/lace/source/events/concrete/lace-observer-instant.adb
Normal file
23
1-base/lace/source/events/concrete/lace-observer-instant.adb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package body lace.Observer.instant
|
||||||
|
is
|
||||||
|
package body Forge
|
||||||
|
is
|
||||||
|
function new_Observer (Name : in Event.observer_Name) return View
|
||||||
|
is
|
||||||
|
Self : constant View := new Item;
|
||||||
|
begin
|
||||||
|
Self.Name := to_unbounded_String (Name);
|
||||||
|
return Self;
|
||||||
|
end new_Observer;
|
||||||
|
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return Event.observer_Name
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return to_String (Self.Name);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
end lace.Observer.instant;
|
||||||
42
1-base/lace/source/events/concrete/lace-observer-instant.ads
Normal file
42
1-base/lace/source/events/concrete/lace-observer-instant.ads
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
with
|
||||||
|
lace.make_Observer,
|
||||||
|
lace.Any;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Strings.unbounded;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Observer.instant
|
||||||
|
--
|
||||||
|
-- Provides a concrete instant event observer.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is limited new Any.limited_item
|
||||||
|
and Observer .item with private;
|
||||||
|
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
|
||||||
|
package Forge
|
||||||
|
is
|
||||||
|
function new_Observer (Name : in Event.observer_Name) return View;
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return Event.observer_Name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
package Observer is new make_Observer (Any.limited_item);
|
||||||
|
|
||||||
|
type Item is limited new Observer.item with
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Observer.instant;
|
||||||
39
1-base/lace/source/events/concrete/lace-subject-local.adb
Normal file
39
1-base/lace/source/events/concrete/lace-subject-local.adb
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package body lace.Subject.local
|
||||||
|
is
|
||||||
|
package body Forge
|
||||||
|
is
|
||||||
|
function to_Subject (Name : in Event.subject_Name) return Item
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self : Item
|
||||||
|
do
|
||||||
|
Self.Name := to_unbounded_String (Name);
|
||||||
|
end return;
|
||||||
|
end to_Subject;
|
||||||
|
|
||||||
|
|
||||||
|
function new_Subject (Name : in Event.subject_Name) return View
|
||||||
|
is
|
||||||
|
Self : constant View := new Item' (to_Subject (Name));
|
||||||
|
begin
|
||||||
|
return Self;
|
||||||
|
end new_Subject;
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure destroy (Self : in out Item)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Subject.destroy (Subject.item (Self)); -- Destroy base class.
|
||||||
|
end destroy;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return Event.subject_Name
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return to_String (Self.Name);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
end lace.Subject.local;
|
||||||
46
1-base/lace/source/events/concrete/lace-subject-local.ads
Normal file
46
1-base/lace/source/events/concrete/lace-subject-local.ads
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
with
|
||||||
|
lace.make_Subject,
|
||||||
|
lace.Any;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Strings.unbounded;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Subject.local
|
||||||
|
--
|
||||||
|
-- Provides a concrete local event Subject.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is limited new Any.limited_item
|
||||||
|
and Subject .item with private;
|
||||||
|
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
|
||||||
|
package Forge
|
||||||
|
is
|
||||||
|
function to_Subject (Name : in Event.subject_Name) return Item;
|
||||||
|
function new_Subject (Name : in Event.subject_Name) return View;
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
procedure destroy (Self : in out Item);
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return Event.subject_Name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
package Subject is new make_Subject (Any.limited_item);
|
||||||
|
|
||||||
|
type Item is limited new Subject.item with
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Subject.local;
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
with
|
||||||
|
ada.unchecked_Deallocation;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Subject_and_deferred_Observer
|
||||||
|
is
|
||||||
|
package body Forge
|
||||||
|
is
|
||||||
|
function to_Subject_and_Observer (Name : in String) return Item
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self : Item
|
||||||
|
do
|
||||||
|
Self.Name := to_unbounded_String (Name);
|
||||||
|
end return;
|
||||||
|
end to_Subject_and_Observer;
|
||||||
|
|
||||||
|
|
||||||
|
function new_Subject_and_Observer (Name : in String) return View
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return new Item' (to_Subject_and_Observer (Name));
|
||||||
|
end new_Subject_and_Observer;
|
||||||
|
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure destroy (Self : in out Item)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Deferred.destroy (Deferred.item (Self)); -- Destroy base classes.
|
||||||
|
Subject .destroy (Subject .item (Self));
|
||||||
|
end destroy;
|
||||||
|
|
||||||
|
|
||||||
|
procedure free (Self : in out View)
|
||||||
|
is
|
||||||
|
procedure deallocate is new ada.unchecked_Deallocation (Item'Class, View);
|
||||||
|
begin
|
||||||
|
Self.destroy;
|
||||||
|
deallocate (Self);
|
||||||
|
end free;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return to_String (Self.Name);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
end lace.Subject_and_deferred_Observer;
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
with
|
||||||
|
lace.Subject,
|
||||||
|
lace.Observer,
|
||||||
|
lace.make_Subject,
|
||||||
|
lace.make_Observer.deferred,
|
||||||
|
lace.Any;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Strings.unbounded;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Subject_and_deferred_Observer
|
||||||
|
--
|
||||||
|
-- Provides a concrete type for a combined event subject and a deferred observer.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is limited new lace.Any.limited_item
|
||||||
|
and lace.Subject .item
|
||||||
|
and lace.Observer .item with private;
|
||||||
|
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
|
||||||
|
package Forge
|
||||||
|
is
|
||||||
|
function to_Subject_and_Observer (Name : in String) return Item;
|
||||||
|
function new_Subject_and_Observer (Name : in String) return View;
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
procedure destroy (Self : in out Item);
|
||||||
|
procedure free (Self : in out View);
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return String;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
package Subject is new make_Subject (Any.limited_item);
|
||||||
|
package Observer is new make_Observer (Subject .item);
|
||||||
|
package Deferred is new Observer.deferred (Observer .item);
|
||||||
|
|
||||||
|
type Item is limited new Deferred.item with
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Subject_and_deferred_Observer;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package body lace.Subject_and_instant_Observer
|
||||||
|
is
|
||||||
|
|
||||||
|
package body Forge
|
||||||
|
is
|
||||||
|
function to_Subject_and_Observer (Name : in String) return Item
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self : Item
|
||||||
|
do
|
||||||
|
Self.Name := to_unbounded_String (Name);
|
||||||
|
end return;
|
||||||
|
end to_Subject_and_Observer;
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return to_String (Self.Name);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
end lace.Subject_and_instant_Observer;
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
with
|
||||||
|
lace.make_Subject,
|
||||||
|
lace.make_Observer,
|
||||||
|
lace.Any,
|
||||||
|
lace.Subject,
|
||||||
|
lace.Observer;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Strings.unbounded;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Subject_and_instant_Observer
|
||||||
|
--
|
||||||
|
-- Provides a concrete type for a combined event subject and an instant observer.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
type Item is limited new lace.Any.limited_item
|
||||||
|
and lace.Subject .item
|
||||||
|
and lace.Observer .item with private;
|
||||||
|
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
|
||||||
|
package Forge
|
||||||
|
is
|
||||||
|
function to_Subject_and_Observer (Name : in String) return Item;
|
||||||
|
end Forge;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Name (Self : in Item) return String;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
use ada.Strings.unbounded;
|
||||||
|
|
||||||
|
package Subject is new make_Subject (Any.limited_item);
|
||||||
|
package Observer is new make_Observer (Subject .item);
|
||||||
|
|
||||||
|
type Item is limited new Observer.item with
|
||||||
|
record
|
||||||
|
Name : unbounded_String;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.Subject_and_instant_Observer;
|
||||||
23
1-base/lace/source/events/interface/lace-observer.adb
Normal file
23
1-base/lace/source/events/interface/lace-observer.adb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
with
|
||||||
|
lace.Event.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Observer
|
||||||
|
is
|
||||||
|
the_Logger : Event.Logger.view;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Logger_is (Now : in Event.Logger.view)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
the_Logger := Now;
|
||||||
|
end Logger_is;
|
||||||
|
|
||||||
|
|
||||||
|
function Logger return Event.Logger.view
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return the_Logger;
|
||||||
|
end Logger;
|
||||||
|
|
||||||
|
end lace.Observer;
|
||||||
69
1-base/lace/source/events/interface/lace-observer.ads
Normal file
69
1-base/lace/source/events/interface/lace-observer.ads
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
with
|
||||||
|
lace.Event,
|
||||||
|
lace.Response;
|
||||||
|
|
||||||
|
limited
|
||||||
|
with
|
||||||
|
lace.Event.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Observer
|
||||||
|
--
|
||||||
|
-- Provides an interface for an event Observer.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Types;
|
||||||
|
|
||||||
|
type Item is limited interface;
|
||||||
|
type View is access all Item'Class;
|
||||||
|
type Views is array (Positive range <>) of View;
|
||||||
|
|
||||||
|
type fast_View is access all Item'Class with Asynchronous;
|
||||||
|
type fast_Views is array (Positive range <>) of fast_View;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
function Name (Self : in Item) return event.observer_Name is abstract;
|
||||||
|
|
||||||
|
|
||||||
|
------------
|
||||||
|
-- Responses
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure add (Self : access Item; the_Response : in Response.view;
|
||||||
|
to_Kind : in event.Kind;
|
||||||
|
from_Subject : in event.subject_Name) is abstract;
|
||||||
|
|
||||||
|
procedure rid (Self : access Item; the_Response : in Response.view;
|
||||||
|
to_Kind : in event.Kind;
|
||||||
|
from_Subject : in event.subject_Name) is abstract;
|
||||||
|
|
||||||
|
procedure relay_responseless_Events
|
||||||
|
(Self : in out Item; To : in Observer.view) is abstract;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure receive (Self : access Item; the_Event : in Event.item'Class := event.null_Event;
|
||||||
|
from_Subject : in event.subject_Name) is abstract;
|
||||||
|
--
|
||||||
|
-- Accepts an Event from a Subject.
|
||||||
|
|
||||||
|
procedure respond (Self : access Item) is abstract;
|
||||||
|
--
|
||||||
|
-- Performs the Response for (and then removes) each pending Event.
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
-- Logging
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure Logger_is (Now : in Event.Logger.view);
|
||||||
|
function Logger return Event.Logger.view;
|
||||||
|
|
||||||
|
end lace.Observer;
|
||||||
14
1-base/lace/source/events/interface/lace-response.adb
Normal file
14
1-base/lace/source/events/interface/lace-response.adb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
with
|
||||||
|
ada.Tags;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Response
|
||||||
|
is
|
||||||
|
|
||||||
|
function Name (Self : in Item) return String
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return ada.Tags.expanded_Name (Item'Class (Self)'Tag);
|
||||||
|
end Name;
|
||||||
|
|
||||||
|
end lace.Response;
|
||||||
35
1-base/lace/source/events/interface/lace-response.ads
Normal file
35
1-base/lace/source/events/interface/lace-response.ads
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
with
|
||||||
|
lace.Event;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Response
|
||||||
|
--
|
||||||
|
-- Provides a base class for all derived event 'response' classes.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Types;
|
||||||
|
|
||||||
|
type Item is abstract tagged limited private;
|
||||||
|
type View is access all Item'class;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
function Name (Self : in Item) return String;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure respond (Self : in out Item; to_Event : in Event.item'Class) is abstract;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
type Item is abstract tagged limited null record;
|
||||||
|
|
||||||
|
end lace.Response;
|
||||||
23
1-base/lace/source/events/interface/lace-subject.adb
Normal file
23
1-base/lace/source/events/interface/lace-subject.adb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
with
|
||||||
|
lace.Event.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Subject
|
||||||
|
is
|
||||||
|
the_Logger : Event.Logger.view;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Logger_is (Now : in Event.Logger.view)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
the_Logger := Now;
|
||||||
|
end Logger_is;
|
||||||
|
|
||||||
|
|
||||||
|
function Logger return Event.Logger.view
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return the_Logger;
|
||||||
|
end Logger;
|
||||||
|
|
||||||
|
end lace.Subject;
|
||||||
74
1-base/lace/source/events/interface/lace-subject.ads
Normal file
74
1-base/lace/source/events/interface/lace-subject.ads
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
with
|
||||||
|
lace.Event,
|
||||||
|
lace.Observer;
|
||||||
|
|
||||||
|
limited
|
||||||
|
with
|
||||||
|
lace.Event.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Subject
|
||||||
|
--
|
||||||
|
-- Provides an interface for an event subject.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Types;
|
||||||
|
|
||||||
|
type Item is limited interface;
|
||||||
|
type View is access all Item'Class;
|
||||||
|
type Views is array (Positive range <>) of View;
|
||||||
|
|
||||||
|
type fast_View is access all Item'Class with Asynchronous;
|
||||||
|
type fast_Views is array (Positive range <>) of fast_View;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Containers
|
||||||
|
--
|
||||||
|
|
||||||
|
type Observer_views is array (Positive range <>) of Observer.view;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
function Name (Self : in Item) return Event.subject_Name is abstract;
|
||||||
|
|
||||||
|
|
||||||
|
------------
|
||||||
|
-- Observers
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure register (Self : access Item; the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind) is abstract;
|
||||||
|
|
||||||
|
procedure deregister (Self : in out Item; the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind) is abstract;
|
||||||
|
|
||||||
|
function Observers (Self : in Item; of_Kind : in Event.Kind) return Observer_views is abstract;
|
||||||
|
function observer_Count (Self : in Item) return Natural is abstract;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure emit (Self : access Item; the_Event : in Event.item'Class := Event.null_Event) is abstract;
|
||||||
|
--
|
||||||
|
-- Communication errors are ignored.
|
||||||
|
|
||||||
|
function emit (Self : access Item; the_Event : in Event.item'Class := Event.null_Event)
|
||||||
|
return Observer_views is abstract;
|
||||||
|
--
|
||||||
|
-- Observers who cannot be communicated with are returned.
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
-- Logging
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure Logger_is (Now : in Event.Logger.view);
|
||||||
|
function Logger return Event.Logger.view;
|
||||||
|
|
||||||
|
end lace.Subject;
|
||||||
13
1-base/lace/source/events/lace-event.adb
Normal file
13
1-base/lace/source/events/lace-event.adb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
with
|
||||||
|
ada.Strings.Hash;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.Event
|
||||||
|
is
|
||||||
|
function Hash (the_Kind : in Kind) return ada.Containers.Hash_type
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return ada.Strings.Hash (String (the_Kind));
|
||||||
|
end Hash;
|
||||||
|
|
||||||
|
end lace.Event;
|
||||||
39
1-base/lace/source/events/lace-event.ads
Normal file
39
1-base/lace/source/events/lace-event.ads
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
with
|
||||||
|
ada.Containers;
|
||||||
|
|
||||||
|
|
||||||
|
package lace.Event
|
||||||
|
--
|
||||||
|
-- The base class for all derived event types.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma Pure;
|
||||||
|
|
||||||
|
type Item is tagged null record;
|
||||||
|
|
||||||
|
null_Event : constant Event.item;
|
||||||
|
|
||||||
|
|
||||||
|
subtype subject_Name is String;
|
||||||
|
subtype observer_Name is String;
|
||||||
|
|
||||||
|
|
||||||
|
procedure destruct (Self : in out Item) is null;
|
||||||
|
|
||||||
|
|
||||||
|
type Kind is new String;
|
||||||
|
--
|
||||||
|
-- Uniquely identifies each derived event class.
|
||||||
|
--
|
||||||
|
-- Each derived event class will have its own Kind.
|
||||||
|
--
|
||||||
|
-- Maps to the extended name of 'ada.Tags.Tag_type' value of each derived
|
||||||
|
-- event class (see 'Conversions' section in 'lace.Event.utility').
|
||||||
|
|
||||||
|
function Hash (the_Kind : in Kind) return ada.Containers.Hash_type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
null_Event : constant Event.item := (others => <>);
|
||||||
|
end lace.Event;
|
||||||
243
1-base/lace/source/events/mixin/lace-make_observer.adb
Normal file
243
1-base/lace/source/events/mixin/lace-make_observer.adb
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
with
|
||||||
|
lace.Event.Logger,
|
||||||
|
lace.Event.utility,
|
||||||
|
|
||||||
|
ada.unchecked_Conversion,
|
||||||
|
ada.unchecked_Deallocation;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.make_Observer
|
||||||
|
is
|
||||||
|
use type Event.Logger.view;
|
||||||
|
|
||||||
|
|
||||||
|
procedure destroy (Self : in out Item)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.Responses.destroy;
|
||||||
|
end destroy;
|
||||||
|
|
||||||
|
|
||||||
|
------------
|
||||||
|
-- Responses
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure add (Self : access Item; the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.Responses.add (Self, the_Response, to_Kind, from_Subject);
|
||||||
|
end add;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure rid (Self : access Item; the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.Responses.rid (Self, the_Response, to_Kind, from_Subject);
|
||||||
|
end rid;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure relay_responseless_Events (Self : in out Item; To : in Observer.view)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.Responses.relay_responseless_Events (To);
|
||||||
|
end relay_responseless_Events;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure receive (Self : access Item; the_Event : in Event.item'Class := Event.null_Event;
|
||||||
|
from_Subject : in Event.subject_Name)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.Responses.receive (Self, the_Event, from_Subject);
|
||||||
|
end receive;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure respond (Self : access Item)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
null; -- This is a null operation since there can never be any deferred events for an 'instant' observer.
|
||||||
|
end respond;
|
||||||
|
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
-- Safe Responses
|
||||||
|
--
|
||||||
|
protected
|
||||||
|
body safe_Responses
|
||||||
|
is
|
||||||
|
procedure destroy
|
||||||
|
is
|
||||||
|
use subject_Maps_of_event_responses;
|
||||||
|
|
||||||
|
procedure free is new ada.unchecked_Deallocation (event_response_Map,
|
||||||
|
event_response_Map_view);
|
||||||
|
|
||||||
|
Cursor : subject_Maps_of_event_responses.Cursor := my_Responses.First;
|
||||||
|
the_Map : event_response_Map_view;
|
||||||
|
begin
|
||||||
|
while has_Element (Cursor)
|
||||||
|
loop
|
||||||
|
the_Map := Element (Cursor);
|
||||||
|
free (the_Map);
|
||||||
|
|
||||||
|
next (Cursor);
|
||||||
|
end loop;
|
||||||
|
end destroy;
|
||||||
|
|
||||||
|
|
||||||
|
------------
|
||||||
|
-- Responses
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure add (Self : access Item'Class;
|
||||||
|
the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
if not my_Responses.contains (from_Subject)
|
||||||
|
then
|
||||||
|
my_Responses.insert (from_Subject,
|
||||||
|
new event_response_Map);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
my_Responses.Element (from_Subject).insert (to_Kind,
|
||||||
|
the_Response);
|
||||||
|
if Observer.Logger /= null
|
||||||
|
then
|
||||||
|
Observer.Logger.log_new_Response (the_Response,
|
||||||
|
Observer.item'Class (Self.all),
|
||||||
|
to_Kind,
|
||||||
|
from_Subject);
|
||||||
|
end if;
|
||||||
|
end add;
|
||||||
|
|
||||||
|
|
||||||
|
procedure rid (Self : access Item'Class;
|
||||||
|
the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
my_Responses.Element (from_Subject).delete (to_Kind);
|
||||||
|
|
||||||
|
if Observer.Logger /= null
|
||||||
|
then
|
||||||
|
Observer.Logger.log_rid_Response (the_Response,
|
||||||
|
Observer.item'Class (Self.all),
|
||||||
|
to_Kind,
|
||||||
|
from_Subject);
|
||||||
|
end if;
|
||||||
|
end rid;
|
||||||
|
|
||||||
|
|
||||||
|
procedure relay_responseless_Events (To : in Observer.view)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
my_relay_Target := To;
|
||||||
|
end relay_responseless_Events;
|
||||||
|
|
||||||
|
|
||||||
|
function relay_Target return Observer.view
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return my_relay_Target;
|
||||||
|
end relay_Target;
|
||||||
|
|
||||||
|
|
||||||
|
function Contains (Subject : in Event.subject_Name) return Boolean
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return my_Responses.Contains (Subject);
|
||||||
|
end Contains;
|
||||||
|
|
||||||
|
|
||||||
|
function Element (Subject : in Event.subject_Name) return event_response_Map
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return my_Responses.Element (Subject).all;
|
||||||
|
end Element;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure receive (Self : access Item'Class;
|
||||||
|
the_Event : in Event.item'Class := Event.null_Event;
|
||||||
|
from_Subject : in Event.subject_Name)
|
||||||
|
is
|
||||||
|
use event_response_Maps,
|
||||||
|
subject_Maps_of_event_responses,
|
||||||
|
lace.Event.utility,
|
||||||
|
ada.Containers;
|
||||||
|
|
||||||
|
use type lace.Observer.view;
|
||||||
|
|
||||||
|
the_Responses : event_response_Map renames my_Responses.Element (from_Subject).all;
|
||||||
|
the_Response : constant event_response_Maps.Cursor := the_Responses.find (to_Kind (the_Event'Tag));
|
||||||
|
|
||||||
|
my_Name : constant String := Observer.item'Class (Self.all).Name;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if has_Element (the_Response)
|
||||||
|
then
|
||||||
|
Element (the_Response).respond (the_Event);
|
||||||
|
|
||||||
|
if Observer.Logger /= null
|
||||||
|
then
|
||||||
|
Observer.Logger.log_Response (Element (the_Response),
|
||||||
|
Observer.view (Self),
|
||||||
|
the_Event,
|
||||||
|
from_Subject);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
elsif relay_Target /= null
|
||||||
|
then
|
||||||
|
-- Self.relay_Target.notify (the_Event, from_Subject_Name); -- todo: Re-enable event relays.
|
||||||
|
|
||||||
|
if Observer.Logger /= null
|
||||||
|
then
|
||||||
|
Observer.Logger.log ("[Warning] ~ Relayed events are currently disabled.");
|
||||||
|
else
|
||||||
|
raise program_Error with "Event relaying is currently disabled.";
|
||||||
|
end if;
|
||||||
|
|
||||||
|
else
|
||||||
|
if Observer.Logger /= null
|
||||||
|
then
|
||||||
|
Observer.Logger.log ("[Warning] ~ Observer " & my_Name & " has no response to " & Name_of (the_Event)
|
||||||
|
& " from " & from_Subject & ".");
|
||||||
|
Observer.Logger.log (" count of responses =>" & the_Responses.Length'Image);
|
||||||
|
else
|
||||||
|
raise program_Error with "Observer " & my_Name & " has no response to " & Name_of (the_Event)
|
||||||
|
& " from " & from_Subject & ".";
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when constraint_Error =>
|
||||||
|
if Observer.Logger /= null
|
||||||
|
then
|
||||||
|
Observer.Logger.log (my_Name & " has no responses for events from " & from_Subject & ".");
|
||||||
|
else
|
||||||
|
raise Program_Error with my_Name & " has no responses for events from " & from_Subject & ".";
|
||||||
|
end if;
|
||||||
|
end receive;
|
||||||
|
|
||||||
|
end safe_Responses;
|
||||||
|
|
||||||
|
|
||||||
|
end lace.make_Observer;
|
||||||
138
1-base/lace/source/events/mixin/lace-make_observer.ads
Normal file
138
1-base/lace/source/events/mixin/lace-make_observer.ads
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
with
|
||||||
|
lace.Event,
|
||||||
|
lace.Response,
|
||||||
|
lace.Observer;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Containers.indefinite_hashed_Maps,
|
||||||
|
ada.Strings.Hash;
|
||||||
|
|
||||||
|
|
||||||
|
generic
|
||||||
|
type T is abstract tagged limited private;
|
||||||
|
|
||||||
|
package lace.make_Observer
|
||||||
|
--
|
||||||
|
-- Makes a user class T into an event Observer.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Types;
|
||||||
|
|
||||||
|
type Item is abstract limited new T
|
||||||
|
and Observer.item with private;
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
|
||||||
|
procedure destroy (Self : in out Item);
|
||||||
|
|
||||||
|
|
||||||
|
------------
|
||||||
|
-- Responses
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure add (Self : access Item; the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name);
|
||||||
|
overriding
|
||||||
|
procedure rid (Self : access Item; the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name);
|
||||||
|
overriding
|
||||||
|
procedure relay_responseless_Events (Self : in out Item; To : in Observer.view);
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure receive (Self : access Item; the_Event : in Event.item'Class := event.null_Event;
|
||||||
|
from_Subject : in Event.subject_Name);
|
||||||
|
overriding
|
||||||
|
procedure respond (Self : access Item);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
----------------------
|
||||||
|
-- Event response maps
|
||||||
|
--
|
||||||
|
use type event.Kind;
|
||||||
|
use type Response.view;
|
||||||
|
|
||||||
|
package event_response_Maps is new ada.Containers.indefinite_hashed_Maps (key_type => Event.Kind,
|
||||||
|
element_type => Response.view,
|
||||||
|
hash => Event.Hash,
|
||||||
|
equivalent_keys => "=");
|
||||||
|
subtype event_response_Map is event_response_Maps.Map;
|
||||||
|
type event_response_Map_view is access all event_response_Map;
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------
|
||||||
|
-- Subject maps of event responses
|
||||||
|
--
|
||||||
|
|
||||||
|
package subject_Maps_of_event_responses
|
||||||
|
is new ada.Containers.indefinite_hashed_Maps (key_type => Event.subject_Name,
|
||||||
|
element_type => event_response_Map_view,
|
||||||
|
hash => ada.Strings.Hash,
|
||||||
|
equivalent_keys => "=");
|
||||||
|
subtype subject_Map_of_event_responses is subject_Maps_of_event_responses.Map;
|
||||||
|
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
-- Safe Responses
|
||||||
|
--
|
||||||
|
protected
|
||||||
|
type safe_Responses
|
||||||
|
is
|
||||||
|
procedure destroy;
|
||||||
|
|
||||||
|
------------
|
||||||
|
-- Responses
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure add (Self : access Item'Class;
|
||||||
|
the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name);
|
||||||
|
|
||||||
|
procedure rid (Self : access Item'Class;
|
||||||
|
the_Response : in Response.view;
|
||||||
|
to_Kind : in Event.Kind;
|
||||||
|
from_Subject : in Event.subject_Name);
|
||||||
|
|
||||||
|
procedure relay_responseless_Events (To : in Observer.view);
|
||||||
|
|
||||||
|
function relay_Target return Observer.view;
|
||||||
|
|
||||||
|
function Contains (Subject : in Event.subject_Name) return Boolean;
|
||||||
|
function Element (Subject : in Event.subject_Name) return event_response_Map;
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
procedure receive (Self : access Item'Class;
|
||||||
|
the_Event : in Event.item'Class := Event.null_Event;
|
||||||
|
from_Subject : in Event.subject_Name);
|
||||||
|
|
||||||
|
private
|
||||||
|
my_Responses : subject_Map_of_event_responses;
|
||||||
|
my_relay_Target : Observer.view;
|
||||||
|
end safe_Responses;
|
||||||
|
|
||||||
|
|
||||||
|
----------------
|
||||||
|
-- Observer Item
|
||||||
|
--
|
||||||
|
type Item is abstract limited new T
|
||||||
|
and Observer.item
|
||||||
|
with
|
||||||
|
record
|
||||||
|
Responses : safe_Responses;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.make_Observer;
|
||||||
240
1-base/lace/source/events/mixin/lace-make_subject.adb
Normal file
240
1-base/lace/source/events/mixin/lace-make_subject.adb
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
with
|
||||||
|
lace.Event.Logger,
|
||||||
|
lace.Event.utility,
|
||||||
|
system.RPC,
|
||||||
|
ada.unchecked_Deallocation;
|
||||||
|
|
||||||
|
|
||||||
|
package body lace.make_Subject
|
||||||
|
is
|
||||||
|
use type Event.Logger.view;
|
||||||
|
|
||||||
|
|
||||||
|
procedure destroy (Self : in out Item)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.safe_Observers.destruct;
|
||||||
|
end destroy;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Observers (Self : in Item; of_Kind : in Event.Kind) return subject.Observer_views
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self.safe_Observers.fetch_Observers (of_Kind);
|
||||||
|
end Observers;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function observer_Count (Self : in Item) return Natural
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
return Self.safe_Observers.observer_Count;
|
||||||
|
end observer_Count;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure register (Self : access Item; the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.safe_Observers.add (the_Observer, of_Kind);
|
||||||
|
|
||||||
|
if Subject.Logger /= null
|
||||||
|
then
|
||||||
|
Subject.Logger.log_Connection (the_Observer,
|
||||||
|
Subject.view (Self),
|
||||||
|
of_Kind);
|
||||||
|
end if;
|
||||||
|
end register;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure deregister (Self : in out Item; the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind)
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
Self.safe_Observers.rid (the_Observer, of_Kind);
|
||||||
|
|
||||||
|
if Subject.Logger /= null
|
||||||
|
then
|
||||||
|
Subject.Logger.log_disconnection (the_Observer,
|
||||||
|
Self'unchecked_Access,
|
||||||
|
of_Kind);
|
||||||
|
end if;
|
||||||
|
end deregister;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure emit (Self : access Item; the_Event : in Event.item'Class := Event.null_Event)
|
||||||
|
is
|
||||||
|
use lace.Event.utility;
|
||||||
|
my_Observers : constant Subject.Observer_views := Self.Observers (to_Kind (the_Event'Tag));
|
||||||
|
begin
|
||||||
|
for i in my_Observers'Range
|
||||||
|
loop
|
||||||
|
begin
|
||||||
|
my_Observers (i).receive (the_Event,
|
||||||
|
from_Subject => Subject.item'Class (Self.all).Name);
|
||||||
|
if Subject.Logger /= null
|
||||||
|
then
|
||||||
|
Subject.Logger.log_Emit (Subject.view (Self),
|
||||||
|
my_Observers (i),
|
||||||
|
the_Event);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error
|
||||||
|
| storage_Error =>
|
||||||
|
if Subject.Logger /= null
|
||||||
|
then
|
||||||
|
Subject.Logger.log_Emit (Subject.view (Self),
|
||||||
|
my_Observers (i),
|
||||||
|
the_Event);
|
||||||
|
end if;
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
end emit;
|
||||||
|
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function emit (Self : access Item; the_Event : in Event.item'Class := Event.null_Event)
|
||||||
|
return subject.Observer_views
|
||||||
|
is
|
||||||
|
use lace.Event.utility;
|
||||||
|
my_Observers : constant Subject.Observer_views := Self.Observers (to_Kind (the_Event'Tag));
|
||||||
|
bad_Observers : Subject.Observer_views (my_Observers'Range);
|
||||||
|
bad_Count : Natural := 0;
|
||||||
|
begin
|
||||||
|
for i in my_Observers'Range
|
||||||
|
loop
|
||||||
|
begin
|
||||||
|
my_Observers (i).receive (the_Event,
|
||||||
|
from_Subject => Subject.item'Class (Self.all).Name);
|
||||||
|
if Subject.Logger /= null
|
||||||
|
then
|
||||||
|
Subject.Logger.log_Emit (Subject.view (Self),
|
||||||
|
my_Observers (i),
|
||||||
|
the_Event);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
exception
|
||||||
|
when system.RPC.communication_Error
|
||||||
|
| storage_Error =>
|
||||||
|
bad_Count := bad_Count + 1;
|
||||||
|
bad_Observers (bad_Count) := my_Observers (i);
|
||||||
|
end;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return bad_Observers (1 .. bad_Count);
|
||||||
|
end emit;
|
||||||
|
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
-- Safe Observers
|
||||||
|
--
|
||||||
|
|
||||||
|
protected
|
||||||
|
body safe_Observers
|
||||||
|
is
|
||||||
|
procedure destruct
|
||||||
|
is
|
||||||
|
use event_kind_Maps_of_event_observers;
|
||||||
|
|
||||||
|
procedure deallocate is new ada.unchecked_Deallocation (event_Observer_Vector,
|
||||||
|
event_Observer_Vector_view);
|
||||||
|
|
||||||
|
Cursor : event_kind_Maps_of_event_observers.Cursor := the_Observers.First;
|
||||||
|
the_event_Observer_Vector : event_Observer_Vector_view;
|
||||||
|
begin
|
||||||
|
while has_Element (Cursor)
|
||||||
|
loop
|
||||||
|
the_event_Observer_Vector := Element (Cursor);
|
||||||
|
deallocate (the_event_Observer_Vector);
|
||||||
|
|
||||||
|
next (Cursor);
|
||||||
|
end loop;
|
||||||
|
end destruct;
|
||||||
|
|
||||||
|
|
||||||
|
procedure add (the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind)
|
||||||
|
is
|
||||||
|
use event_Observer_Vectors,
|
||||||
|
event_kind_Maps_of_event_observers;
|
||||||
|
|
||||||
|
Cursor : constant event_kind_Maps_of_event_observers.Cursor := the_Observers.find (of_Kind);
|
||||||
|
the_event_Observers : event_Observer_Vector_view;
|
||||||
|
begin
|
||||||
|
if has_Element (Cursor)
|
||||||
|
then
|
||||||
|
the_event_Observers := Element (Cursor);
|
||||||
|
else
|
||||||
|
the_event_Observers := new event_Observer_Vector;
|
||||||
|
the_Observers.insert (of_Kind,
|
||||||
|
the_event_Observers);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
the_event_Observers.append (the_Observer);
|
||||||
|
end add;
|
||||||
|
|
||||||
|
|
||||||
|
procedure rid (the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind)
|
||||||
|
is
|
||||||
|
the_event_Observers : event_Observer_Vector renames the_Observers.Element (of_Kind).all;
|
||||||
|
begin
|
||||||
|
the_event_Observers.delete (the_event_Observers.find_Index (the_Observer));
|
||||||
|
end rid;
|
||||||
|
|
||||||
|
|
||||||
|
function fetch_Observers (of_Kind : in Event.Kind) return subject.Observer_views
|
||||||
|
is
|
||||||
|
begin
|
||||||
|
if the_Observers.Contains (of_Kind)
|
||||||
|
then
|
||||||
|
declare
|
||||||
|
the_event_Observers : constant event_Observer_Vector_view := the_Observers.Element (of_Kind);
|
||||||
|
my_Observers : Subject.Observer_views (1 .. Natural (the_event_Observers.Length));
|
||||||
|
begin
|
||||||
|
for i in my_Observers'Range
|
||||||
|
loop
|
||||||
|
my_Observers (i) := the_event_Observers.Element (i);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return my_Observers;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
return [1 .. 0 => <>];
|
||||||
|
end if;
|
||||||
|
end fetch_Observers;
|
||||||
|
|
||||||
|
|
||||||
|
function observer_Count return Natural
|
||||||
|
is
|
||||||
|
use event_kind_Maps_of_event_observers;
|
||||||
|
|
||||||
|
Cursor : event_kind_Maps_of_event_observers.Cursor := the_Observers.First;
|
||||||
|
Count : Natural := 0;
|
||||||
|
begin
|
||||||
|
while has_Element (Cursor)
|
||||||
|
loop
|
||||||
|
Count := Count + Natural (Element (Cursor).Length);
|
||||||
|
next (Cursor);
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return Count;
|
||||||
|
end observer_Count;
|
||||||
|
|
||||||
|
end safe_Observers;
|
||||||
|
|
||||||
|
|
||||||
|
end lace.make_Subject;
|
||||||
114
1-base/lace/source/events/mixin/lace-make_subject.ads
Normal file
114
1-base/lace/source/events/mixin/lace-make_subject.ads
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
with
|
||||||
|
lace.Event,
|
||||||
|
lace.Subject,
|
||||||
|
lace.Observer;
|
||||||
|
|
||||||
|
private
|
||||||
|
with
|
||||||
|
ada.Containers.Vectors,
|
||||||
|
ada.Containers.indefinite_hashed_Maps;
|
||||||
|
|
||||||
|
|
||||||
|
generic
|
||||||
|
type T is abstract tagged limited private;
|
||||||
|
|
||||||
|
package lace.make_Subject
|
||||||
|
--
|
||||||
|
-- Makes a user class T into an event Subject.
|
||||||
|
--
|
||||||
|
is
|
||||||
|
pragma remote_Types;
|
||||||
|
|
||||||
|
type Item is abstract limited new T
|
||||||
|
and Subject.item with private;
|
||||||
|
type View is access all Item'Class;
|
||||||
|
|
||||||
|
procedure destroy (Self : in out Item);
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Attributes
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function Observers (Self : in Item; of_Kind : in Event.Kind) return Subject.Observer_views;
|
||||||
|
overriding
|
||||||
|
function observer_Count (Self : in Item) return Natural;
|
||||||
|
|
||||||
|
|
||||||
|
-------------
|
||||||
|
-- Operations
|
||||||
|
--
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure register (Self : access Item; the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind);
|
||||||
|
overriding
|
||||||
|
procedure deregister (Self : in out Item; the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind);
|
||||||
|
|
||||||
|
overriding
|
||||||
|
procedure emit (Self : access Item; the_Event : in Event.item'Class := Event.null_Event);
|
||||||
|
|
||||||
|
overriding
|
||||||
|
function emit (Self : access Item; the_Event : in Event.item'Class := Event.null_Event)
|
||||||
|
return subject.Observer_views;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
-- Event observer vectors
|
||||||
|
--
|
||||||
|
use type Observer.view;
|
||||||
|
|
||||||
|
package event_Observer_Vectors is new ada.Containers.Vectors (Positive, Observer.view);
|
||||||
|
subtype event_Observer_Vector is event_Observer_Vectors.Vector;
|
||||||
|
type event_Observer_Vector_view is access all event_Observer_Vector;
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------
|
||||||
|
-- Event kind Maps of event observers
|
||||||
|
--
|
||||||
|
use type Event.Kind;
|
||||||
|
package event_kind_Maps_of_event_observers is new ada.Containers.indefinite_hashed_Maps (Event.Kind,
|
||||||
|
event_Observer_Vector_view,
|
||||||
|
Event.Hash,
|
||||||
|
"=");
|
||||||
|
subtype event_kind_Map_of_event_observers is event_kind_Maps_of_event_observers.Map;
|
||||||
|
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
-- Safe observers
|
||||||
|
--
|
||||||
|
protected
|
||||||
|
type safe_Observers
|
||||||
|
is
|
||||||
|
procedure destruct;
|
||||||
|
|
||||||
|
procedure add (the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind);
|
||||||
|
|
||||||
|
procedure rid (the_Observer : in Observer.view;
|
||||||
|
of_Kind : in Event.Kind);
|
||||||
|
|
||||||
|
function fetch_Observers (of_Kind : in Event.Kind) return Subject.Observer_views;
|
||||||
|
function observer_Count return Natural;
|
||||||
|
|
||||||
|
private
|
||||||
|
the_Observers : event_kind_Map_of_event_observers;
|
||||||
|
end safe_Observers;
|
||||||
|
|
||||||
|
|
||||||
|
---------------
|
||||||
|
-- Subject Item
|
||||||
|
--
|
||||||
|
type Item is abstract limited new T
|
||||||
|
and Subject.item
|
||||||
|
with
|
||||||
|
record
|
||||||
|
safe_Observers : make_Subject.safe_Observers;
|
||||||
|
end record;
|
||||||
|
|
||||||
|
end lace.make_Subject;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user