with Ada.Streams;
package Object is
use Ada.Streams;
-- Point --
type Point is tagged record
X, Y : Float;
end record;
procedure Class_Output
(S : access Ada.Streams.Root_Stream_Type'Class; O : in Point'Class);
for Point'Class'Output use Class_Output;
function Class_Input
(S : access Ada.Streams.Root_Stream_Type'Class) return Point'Class;
for Point'Class'Input use Class_Input;
for Point'External_Tag use "point";
procedure Write
(S : access Root_Stream_Type'Class; O : in Point);
for Point'Write use Write;
procedure Read (S : access Root_Stream_Type'Class; O : out Point);
for Point'Read use Read;
procedure Display (O : in Point);
-- Pixel --
type Color_Name is (Red, Green, Blue);
type Pixel is new Point with record
Color : Color_Name;
end record;
for Pixel'External_Tag use "pixel";
procedure Write
(S : access Root_Stream_Type'Class; O : in Pixel);
for Pixel'Write use Write;
procedure Read (S : access Root_Stream_Type'Class; O : out Pixel);
for Pixel'Read use Read;
overriding procedure Display (O : in Pixel);
end Object;
with Ada.Tags.Generic_Dispatching_Constructor;
with Ada.Text_IO;
with Ada.Text_IO.Text_Streams;
package body Object is
use Ada.Text_IO;
------------------------------------------- XML parsing helper functions
procedure Skip_Tag
(S : access Ada.Streams.Root_Stream_Type'Class;
Ending : in Character := '>');
-- Skip the next tag on stream S, returns when Ending is found
function Get_Value
(S : access Ada.Streams.Root_Stream_Type'Class) return String;
-- Returns the current value read on stream S
--------------
-- Skip_Tag --
--------------
procedure Skip_Tag
(S : access Ada.Streams.Root_Stream_Type'Class;
Ending : in Character := '>')
is
C : Character;
begin
loop
Character'Read (S, C);
exit when C = Ending;
end loop;
end Skip_Tag;
---------------
-- Get_Value --
---------------
function Get_Value
(S : access Ada.Streams.Root_Stream_Type'Class) return String
is
Buffer : String (1 .. 100);
K : Positive := Buffer'First;
begin
loop
Character'Read (S, Buffer (K));
exit when Buffer (K) = '<';
K := K + 1;
end loop;
return Buffer (1 .. K - 1);
end Get_Value;
------------------------------------------- Point'Class
------------------
-- Class_Output --
------------------
procedure Class_Output
(S : access Ada.Streams.Root_Stream_Type'Class; O : in Point'Class) is
begin
-- Write the opening tag
Character'Write (S, '<');
String'Write (S, Ada.Tags.External_Tag (O'Tag));
String'Write (S, '>' & ASCII.LF);
-- Write the object, dispatching call to Point/Pixel'Write
Point'Output (S, O);
-- Write the closing tag
String'Write (S, "");
String'Write (S, Ada.Tags.External_Tag (O'Tag));
String'Write (S, '>' & ASCII.LF);
end Class_Output;
-----------------
-- Class_Input --
-----------------
function Class_Input
(S : access Ada.Streams.Root_Stream_Type'Class) return Point'Class
is
function Dispatching_Input is
new Ada.Tags.Generic_Dispatching_Constructor
(T => Point,
Parameters => Ada.Streams.Root_Stream_Type'Class,
Constructor => Point'Input);
Input : String (1 .. 20);
Input_Len : Natural := 0;
begin
-- On the stream we have , we want to get "tag_name"
-- Read first character, must be '<'
Character'Read (S, Input (1));
if Input (1) /= '<' then
raise Ada.Tags.Tag_Error with "Starting with " & Input (1);
end if;
-- Read tag
Input_Len := 0;
for I in Input'range loop
Character'Read (S, Input (I));
Input_Len := I;
exit when Input (I) = '>';
end loop;
-- Check ending tag
if Input (Input_Len) /= '>'
or else Input_Len <= 1
then -- Empty tag
raise Ada.Tags.Tag_Error with "empty tag";
else
Input_Len := Input_Len - 1;
end if;
declare
External_Tag : constant String := Input (1 .. Input_Len);
O : constant Point'Class := Dispatching_Input
(Ada.Tags.Internal_Tag (External_Tag), S);
-- Dispatches to appropriate Point/Pixel'Input depending on
-- the tag name.
begin
-- Skip closing object tag
Skip_Tag (S, ASCII.LF);
return O;
end;
end Class_Input;
------------------------------------------- Point
-------------
-- Display --
-------------
procedure Display (O : in Point) is
begin
Put_Line ("*** A point");
Point'Output (Text_Streams.Stream (Current_Output), O);
end Display;
----------
-- Read --
----------
procedure Read (S : access Root_Stream_Type'Class; O : out Point) is
begin
Skip_Tag (S); O.X := Float'Value (Get_Value (S)); Skip_Tag (S, ASCII.LF);
Skip_Tag (S); O.Y := Float'Value (Get_Value (S)); Skip_Tag (S, ASCII.LF);
end Read;
-----------
-- Write --
-----------
procedure Write (S : access Root_Stream_Type'Class; O : in Point) is
begin
String'Write (S, " " & Float'Image (O.X) & "" & ASCII.LF);
String'Write (S, " " & Float'Image (O.Y) & "" & ASCII.LF);
end Write;
------------------------------------------- Pixel
-------------
-- Display --
-------------
overriding procedure Display (O : in Pixel) is
begin
Put_Line ("*** A pixel");
Pixel'Output (Text_Streams.Stream (Current_Output), O);
end Display;
----------
-- Read --
----------
procedure Read (S : access Root_Stream_Type'Class; O : out Pixel) is
begin
Read (S, Point (O));
Skip_Tag (S);
O.Color := Color_Name'Value (Get_Value (S));
Skip_Tag (S, ASCII.LF);
end Read;
-----------
-- Write --
-----------
procedure Write (S : access Root_Stream_Type'Class; O : in Pixel) is
begin
Write (S, Point (O));
String'write
(S, " "
& Color_Name'Image (O.Color) & "" & ASCII.LF);
end Write;
end Object;
with Ada.Text_IO;
with Ada.Text_IO.Text_Streams;
with Object;
procedure Main is
use Ada;
use Ada.Text_IO;
use Object;
File : Text_IO.File_Type;
begin
-- Write some objects
declare
P : Point := (6.8, 0.1);
CP : Pixel := (1.2, 8.4, Red);
begin
Create (File, Out_File, "data");
Point'Class'Output (Text_Streams.Stream (File), CP);
Point'Class'Output (Text_Streams.Stream (File), P);
Close (File);
end;
-- Read them back
Open (File, In_File, "data");
declare
P1 : constant Point'Class :=
Point'Class'Input (Text_Streams.Stream (File));
P2 : constant Point'Class :=
Point'Class'Input (Text_Streams.Stream (File));
begin
P1.Display; New_Line;
P2.Display; New_Line;
end;
Close (File);
end Main;