* wait does not perform as expected
@ 2023-02-22 16:34 6% Daniel Gaudry
0 siblings, 0 replies; 35+ results
From: Daniel Gaudry @ 2023-02-22 16:34 UTC (permalink / raw)
hi
the following code :
with Gnat.Os_Lib;
with Ada.Strings;
with Ada.Strings.Fixed;
with Ada.Strings.Maps;
with Ada.Strings.Maps.Constants;
with ada.text_io;
with Ada.Strings;
procedure Hit_Return_To_Continue(Header : in String := "HIT RETURN TO CONTINUE";
Mandatory : in Boolean := False;
Skip_After : in Duration := 0.0)
is
Char : Character := ' ';
Hit : Boolean := True;
Timer : Duration := 0.0;
begin
-- ANYTHING TO DO ?
if Mandatory
then
ada.text_io.Put(Header);
-- ANY WAITING PERIOD TO DISPLAY ?
if Skip_After > 0.0
then
-- KEEP THE USER'S ATTENTION
while Timer < Skip_After loop
Timer := 1.0 + @;
delay 1.0;
ada.text_io.Put(Natural(Skip_After - Timer)'Img);
--USER ENDS THE WAITING PERIOD BEFORE IT'S END ?
TIO.LOOK_AHEAD(ITEM => CHAR,
END_OF_LINE => HIT);
ada.text_io.GET_IMMEDIATE(ITEM => CHAR,
AVAILABLE => HIT);
IF HIT THEN
RETURN;
END IF;
end loop;
-- USER WAITED FOR THE WHOLE WAITING PERIOD
-- LET HIM READ THE ZERO ON THE SCREEN
delay 1.0;
return;
end if;
Atio.Get_Immediate(Item => Char,
Available => Hit);
Atio.New_Line(Spacing => 1);
end if;
end Hit_Return_To_Continue;
the following call:
Hit_Return_To_Continue(Header => "HIT RETURN TO CONTINUE",
Mandatory => true,
Skip_After => 5.0);
does not return if the user hits a key before the end of the countdown.
Can anybody help
Best regards
^ permalink raw reply [relevance 6%]
* Re: CONSTRAINT ERROR? access check failed
@ 2018-03-01 12:44 5% ` Mehdi Saada
0 siblings, 0 replies; 35+ results
From: Mehdi Saada @ 2018-03-01 12:44 UTC (permalink / raw)
Those are the two last things I would like you people to review. First, I can't get out of that loop, even with the exit INNER; after "Rentrez vos commandes". It starts it again.
INNER : loop
declare
NOM_FICHIER : String := Get_Line;
INDICE : NATURAL := 0;
begin
if Index_Non_Blank (NOM_FICHIER) /= 0
then
if not Exists (NOM_FICHIER) then Put_Line ("N'existe pas. Recommencez."); end if;
OPEN (FILE_ENTREE, In_File, NOM_FICHIER);
Set_Input (FILE_ENTREE);
while not End_Of_File loop
INDICE := INDICE + 10;
INSERT_OR_REPLACE (INDICE, LET_ONLY_GRAPHIC_CHARACTERS(GET_LINE));
end loop;
end if;
Put_Line ("Rentrer maintenant vos commandes"); exit INNER;
exception when others => Put_Line ("ERREUR");
end;
end loop INNER;
Then, could you tell what you think of that subprogram that is meant to purge a STRING from non graphic characters (those that make the program crash) ?
function LET_ONLY_GRAPHIC_CHARACTERS
(INPUT_STRING : in STRING) return STRING is
use Ada.Strings.Maps.Constants,
Ada.Strings.Maps, Ada.Strings.Fixed, Ada.Strings;
FIRST, I, COUNT, LAST : NATURal := INPUT_STRING'FIRST;
OUTPUT_STRING : STRING (INPUT_STRING'Range);
begin
loop
FIND_TOKEN (Source => INPUT_STRING (I .. INPUT_STRING'LAST),
Set => Graphic_Set,
Test => Inside ,
First => First,
Last => Last);
if Last in INPUT_STRING'Range and LAST /= 0 then
OUTPUT_STRING (I .. I + LAST - FIRST) := INPUT_STRING (FIRST .. LAST);
I := I + LAST - FIRST + 1;
else
exit; end if;
end loop;
PRAGMA Assert (Index (OUTPUT_STRING(OUTPUT_STRING'First ..
(if I > OUTPUT_STRING'Length then OUTPUT_STRING'Last else I))
, GRAPHIC_SET, TEST => Outside) = 0, "CHARACTÈRES NON GRAPHIQUE ONT ECHAPPÉS !");
return OUTPUT_STRING (OUTPUT_STRING'First .. (if I > OUTPUT_STRING'Length then OUTPUT_STRING'Last else I));
end;
^ permalink raw reply [relevance 5%]
* Re: Question on bounded / unbounded strings
2016-09-14 11:23 6% ` Arie van Wingerden
@ 2016-09-14 12:57 6% ` Arie van Wingerden
1 sibling, 0 replies; 35+ results
From: Arie van Wingerden @ 2016-09-14 12:57 UTC (permalink / raw)
I finished the program.
It appears to be working correctly (only in Windows, because of the path
separator).
Any comments to improve?
Code follows:
===========
with Ada.Text_Io;
with Ada.Environment_Variables;
with Ada.Strings.Fixed;
with Ada.Strings.Maps.Constants;
procedure Fip is
package ATIO renames Ada.Text_IO;
package AEV renames Ada.Environment_Variables;
package ASF renames Ada.Strings.Fixed;
package ASMC renames Ada.Strings.Maps.Constants;
Path : string := ASF.Translate(AEV.Value("Path"),
ASMC.Lower_Case_Map);
Match : string := ASF.Translate(ATIO.Get_Line, ASMC.Lower_Case_Map);
procedure FindMatch (Match : in string; Path : in string; StartPos : in
positive; Len : in natural) is
EndPos : positive;
begin
if Len > 0 then -- Ignore case of an unnecessary semi colon
EndPos := StartPos + Len - 1;
if ASF.Index(Source => Path(StartPos .. EndPos), Pattern =>
Match) > 0 then
ATIO.Put_Line(Path(StartPos .. EndPos));
end if;
end if;
end FindMatch;
procedure Match_Path (Match : in string; Path : in string) is
StartPos : positive := 1;
Len : natural := 0;
begin
for I in Path'Range loop
if Path(I) = ';' then
FindMatch(Match, Path, StartPos, Len);
StartPos := I + 1;
Len := 0;
else
Len := Len + 1;
end if;
end loop;
end Match_Path;
begin
Match_Path(Match, Path);
ATIO.Flush;
end Fip;
^ permalink raw reply [relevance 6%]
* Re: Question on bounded / unbounded strings
@ 2016-09-14 11:23 6% ` Arie van Wingerden
2016-09-14 12:57 6% ` Arie van Wingerden
1 sibling, 0 replies; 35+ results
From: Arie van Wingerden @ 2016-09-14 11:23 UTC (permalink / raw)
Hi,
thank you *very* much. You are very helpful!
I created the following program, which only uses standard strings. It works
partly.
There is one thing I cannot get to work properly:
in the FOR loop the statement:
ATIO.Put(Path(Start .. Len));
outputs the first part of Path properly; but in the following cases it
won't.
What am I doing wrong?
(Don't mind the matching; this is NOT correct currently).
(Wrongly indented pieces will be gone in final version.)
The program code (FIP stand for Find In Path):
======================================
with Ada.Text_Io;
with Ada.Integer_Text_Io;
with Ada.Environment_Variables;
with Ada.Strings.Fixed;
with Ada.Strings.Maps.Constants;
procedure Fip is
package ATIO renames Ada.Text_IO;
package AITIO renames Ada.Integer_Text_Io;
package AEV renames Ada.Environment_Variables;
package ASF renames Ada.Strings.Fixed;
package ASMC renames Ada.Strings.Maps.Constants;
Path : string := ASF.Translate(AEV.Value("Path"),
ASMC.Lower_Case_Map);
Match : string := ASF.Translate(ATIO.Get_Line, ASMC.Lower_Case_Map);
procedure Match_Path (Match : in string; Path : in string) is
Start : positive := 1;
Len : natural := 0;
begin
for I in Path'Range loop
if Path(I) = ';' then
ATIO.Put_Line("----------------------------------------------------");
ATIO.Put(Path(Start .. Len)); AITIO.Put(Start); AITIO.Put(Len); ATIO.Put("
"); ATIO.Put_Line(Match);
-- This matching part is not OK yet
if Len > 0 and then Path(Start .. Len) = Match then
ATIO.Put_Line(Path(Start .. Len));
end if;
Start := I + 1;
Len := 0;
else
Len := Len + 1;
end if;
end loop;
end Match_Path;
begin
Match_Path(Match, Path);
ATIO.Flush;
end Fip;
^ permalink raw reply [relevance 6%]
* Re: OpenToken: Parsing Ada (subset)?
2015-06-01 13:08 5% OpenToken: Parsing Ada (subset)? Jacob Sparre Andersen
@ 2015-06-02 22:12 4% ` Stephen Leake
0 siblings, 0 replies; 35+ results
From: Stephen Leake @ 2015-06-02 22:12 UTC (permalink / raw)
Jacob Sparre Andersen <sparre@nbi.dk> writes:
> I'm attempting to use OpenToken to parse an Ada subset without much
> success.
(Shameless plug) An alternative approach is to start from the full Ada
grammar in Emacs ada-mode (ada-grammar.wy), and reduce it to what you
want. You'd also have to change the actions; they are focused on
supporting indentation and navigation in Emacs.
That grammar is in a .wy file, which must be processed by wisi-generate
to produce Ada code. The code produced by wisi-generate does not support
Ada actions at the moment (it only supports Emacs elisp, or a process or
dll communicating with Emacs), but you could either add that to
wisi-generate or treat the generated code as a template and add your own
actions.
wisi-generate also assumes a single token type, so that changes how you
write the actions (more code in the actions, less in the tokens).
If you want to try adding actions to wisi-generate, I suggest you start
from FastToken (in monotone branch org.fasttoken, no release yet). It is
passing all its tests. I am still working on it, so the code will be
changing quite a bit. I plain to completely eliminate the token type
hierarchy, to avoid the run-time dynamic memory management it requires.
But that should be mostly orthogonal to actions. I'd be happy to help
with this; it is on my list of things to do someday, and having an
actual user is fun :).
> Identifier_T =>
> Tokenizer.Get (OpenToken.Recognizer.Identifier.Get
> (Start_Chars => Ada.Strings.Maps.Constants.Letter_Set,
> Body_Chars => Ada.Strings.Maps.Constants.Alphanumeric_Set)),
This line says to use the default 'Get' routine to specify the token
type to use for Identifier_T; that is Master_Token.Instance, as you
complain later (see opentoken-token-enumerated-analyzer.ads:88). Change
to:
Identifier_T =>
Tokenizer.Get
(OpenToken.Recognizer.Identifier.Get
(Start_Chars => Ada.Strings.Maps.Constants.Letter_Set,
Body_Chars => Ada.Strings.Maps.Constants.Alphanumeric_Set),
Identifiers.Get (Identifier_T),
I hate default parameters in general; this one is sort of convenient
(most terminals are happy being Master_Token.Instance, and you don't
have to repeat Identifier_T), but easily leads to this kind of bug (most
default parameters lead to hard to find bugs!).
Note that the ID parameter to Identifiers.Get could be defaulted; it is
overwritten in Analyzer.Initialize.
To see this in the code; terminal token objects are created on the
parser stack at opentoken-production-parser-lalr-parser.adb:318, as a
copy of a token returned by Analyzer.Get. Analyzer.Get returns the token
stored in the syntax; see opentoken-token-enumerated-analyzer.adb:772.
Nonterminal token objects are created at
opentoken-production-parser-lalr-parser.adb:177, as a copy of the
production left hand side (ie Dotted_Identifier below).
> Identifier : constant Identifiers.Instance'Class := Identifiers.Get (Identifier_T);
>
> I declare the grammar as:
>
> Grammar : constant Production_List.Instance :=
> Compilation_Unit <= Dotted_Identifier & EOF and
> Dotted_Identifier <= Dotted_Identifier & Dot & Identifier + Dotted_Identifiers.Join_Dotted_Identifiers and
> Dotted_Identifier <= Identifier;
You might think that the use of Identifier.Instance here does what you
want, but it doesn't; the grammar determines the types only of the
nonterminals, the syntax determines the types of the terminals.
I suppose I should add that to the OpenToken user manual, but I'd rather
work on the FastToken user manual, which won't have this problem (only
one type for tokens :).
> I'm probably doing something obvious wrong, but what?
Obvious to me, but I've been messing with the lexer code in FastToken
recently; I switched to using regular expressions for the token
recognizers (to be closer to Aflex, which is also now supported). While
doing that, I deleted the default Get above.
Using regular expressions instead of the old OpenToken recognizers is a
big change, but wisi-generate takes care of most of the drudge work for
you (you just have to specify the actual regular expressions).
Glad to hear someone is using OpenToken, and it's fun to actually talk
about this stuff once in a while :).
--
-- Stephe
^ permalink raw reply [relevance 4%]
* OpenToken: Parsing Ada (subset)?
@ 2015-06-01 13:08 5% Jacob Sparre Andersen
2015-06-02 22:12 4% ` Stephen Leake
0 siblings, 1 reply; 35+ results
From: Jacob Sparre Andersen @ 2015-06-01 13:08 UTC (permalink / raw)
I'm attempting to use OpenToken to parse an Ada subset without much
success.
I've reduced my problem all the way down to attempting to parse a
"dotted" identifier:
Example -> Dotted_Identifier EOF
Dotted_Identifier -> Identifier | Dotted_Identifier "." Identifier
I declare the syntax like this (I've removed the reserved words for now):
Syntax : constant Tokenizer.Syntax :=
(Dot_T => Tokenizer.Get (OpenToken.Recognizer.Separator.Get (".")),
Identifier_T => Tokenizer.Get (OpenToken.Recognizer.Identifier.Get
(Start_Chars => Ada.Strings.Maps.Constants.Letter_Set,
Body_Chars => Ada.Strings.Maps.Constants.Alphanumeric_Set)),
Comment_T => Tokenizer.Get (OpenToken.Recognizer.Line_Comment.Get ("--")),
Whitespace_T => Tokenizer.Get (OpenToken.Recognizer.Character_Set.Get
(OpenToken.Recognizer.Character_Set.Standard_Whitespace)),
End_Of_File_T => Tokenizer.Get (OpenToken.Recognizer.End_Of_File.Get));
I declare the token objects (for writing the grammar) like this:
Dot : constant Master_Token.Class := Master_Token.Get (Dot_T);
EOF : constant Master_Token.Class := Master_Token.Get (End_Of_File_T);
Identifier : constant Identifiers.Instance'Class := Identifiers.Get (Identifier_T);
Compilation_Unit : constant Nonterminal.Class := Nonterminal.Get (Compilation_Unit_T);
Dotted_Identifier : constant Dotted_Identifiers.Class := Dotted_Identifiers.Get (Dotted_Identifier_T);
I declare the grammar as:
Grammar : constant Production_List.Instance :=
Compilation_Unit <= Dotted_Identifier & EOF and
Dotted_Identifier <= Dotted_Identifier & Dot & Identifier + Dotted_Identifiers.Join_Dotted_Identifiers and
Dotted_Identifier <= Identifier;
When I attempt to use this grammar to parse a "dotted" identifier, I run
into problems when OpenToken attempts to convert an identifier token to
a Dotted_Identifier.Instance object. The problem which occurs is that
the identifier is represented as a plain Master_Token.Instance object,
which doesn't contain the actual identifier - which means that I can't
copy it into the "dotted" identifier.
I'm using OpenToken 6.0b. The full compilable source (including the
used OpenToken packages) can be downloaded from
<http://jacob.sparre-andersen.dk/temp/ada_parsing_with_opentoken-2015-06-01-a.zip>.
To build the example:
gnatmake parse_dotted_identifier
To test it:
echo Ada.Text_IO.Integer_IO | ./parse_dotted_identifier
I'm probably doing something obvious wrong, but what?
Greetings,
Jacob
--
"It is very easy to get ridiculously confused about the
tenses of time travel, but most things can be resolved
by a sufficiently large ego."
^ permalink raw reply [relevance 5%]
* Re: Practicalities of Ada for app development
@ 2012-06-13 8:37 5% ` Georg Bauhaus
0 siblings, 0 replies; 35+ results
From: Georg Bauhaus @ 2012-06-13 8:37 UTC (permalink / raw)
On 13.06.12 02:04, Adam Beneschan wrote:
> Maybe this should be a challenge to the Ada community to come up with some common package specification (or set of packages) that would be sufficient to meet those needs, so that users wouldn't feel a need to switch to Perl to get the same kind of expressive power. Offhand, I don't think it would need to become part of the official language standard (the letters I, S, and O are not a magical incantation that automatically makes software more trustworthy). We've had working groups in the past that have developed standard packages that weren't part of the language (although some of them became part of later versions of the language, like Ada.Numerics). What does anyone else think? Does this seem worthwhile? I have to admit, I've sometimes been frustrated when I need to work with text, although not enough to get me to use Perl for more than smallish programs, so off the top of my head this seems like it might be useful.
I like the "sufficient for most needs" part very much. It allows
going back to just regular languages.
This is my wishlist for a framework supporting regular languages
built around language features familiar to Ada programmers:
1. The building blocks in Ada.Strings.Maps, Ada.Strings.Maps.Constants
etc seem to correspond to character classes in POSIX REs:
Hexadecimal_Digit_Set ~[0-9A-Fa-f]
Yet, the set operations of Maps exceed what I get in RE packages
of languages that start from version 7 regexp. Good!
So, alternation is presently possible for single characters.
Need groups and sequencing, expressed in the type system.
2. The container mechanics (Ada STL) offer one possible approach
to handling the set of matches:
The matching process results in an object of type that supports
iteration. Perhaps not just Cursors, but also Extended_Index
like in Vectors, because programmers will expect that
groups in patterns are indexed by number.
3. The pattern matching facilities need not go beyond
regular languages. Provide some frequently used constant
patterns, such as end-of-line, start-of-string, word-boundary.
4. Add a single, read-only feature for RE inspection. It allows
observing the scanning process:
For example, given (ABC|BCD)E, and a function "&" returning
a pattern type,
Alternation'(To_Set ("ABC") & To_Set ("BCD"))
& To_Pattern ("E");
Here, it might be helpful to see the backtracking (if any) triggered
when the scanner is about to hit "E". Therefore, allow programmers
to implement an abstract pattern type that matches the empty
string. The scanner will call its primitive subprogram,
thus
Alternation'(To_Set ("ABC") & To_Set ("BCD"))
& user_defined_empty_1
& To_Pattern ("E");
5. Define a small set of well chosen operators that reduce
verbosity. (GNAT's Spitbol.Patterns has quite a lot of them.)
6. Producing new text from input text should not physically rely
on Ada.Strings.Unbounded. Instead, allocate new strings that can
clean up after themselves.
In conclusion, programmers would rely on Ada's type system when expressing
a pattern. They would not be forced to write in yet another macro
language in strings, as is required by most scripting languages.
Access to matched portions of input uses a familiar framework.
^ permalink raw reply [relevance 5%]
* Re: Checking to see is a string is a letter
@ 2012-04-03 7:09 6% ` Thomas Løcke
0 siblings, 0 replies; 35+ results
From: Thomas Løcke @ 2012-04-03 7:09 UTC (permalink / raw)
On 04/03/2012 04:11 AM, deuteros wrote:
> Is there a way to check if a string variable contains a single letter?
A possible solution would be to take a look at Ada.Strings.Maps and
Ada.Strings.Maps.Constants.
You can then use Ada.Strings.Fixed.Count to count the number of matches
against your map, and if the result isn't exactly 1, then you know your
string contains either zero "single letter" or several "single letter".
But first of course you need to define exactly what "single letter"
means.
:o)
--
Thomas L�cke | thomas@12boo.net | http://12boo.net
^ permalink raw reply [relevance 6%]
* ANN: Some updates
@ 2008-03-30 17:13 6% Dmitry A. Kazakov
0 siblings, 0 replies; 35+ results
From: Dmitry A. Kazakov @ 2008-03-30 17:13 UTC (permalink / raw)
Tables 1.8
http://www.dmitry-kazakov.de/ada/tables.htm
Strings Edit 2.1
http://www.dmitry-kazakov.de/ada/strings_edit.htm
Simple components 2.8
http://www.dmitry-kazakov.de/ada/components.htm
Fuzzy sets for Ada 5.2
http://www.dmitry-kazakov.de/ada/fuzzy.htm
The focus of these releases is UTF-8 support. New features include
Tables of case-insensitive tokes, UTF-8 encoded. Tables can be matched
against an UTF-8 encoded strings in order to get the longest alternative.
Chains of blank code points can be considered equivalent. Code points can
be ignored (hyphens, for example). Case equivalence is determined according
to the Unicode categories.
A fully functional UTF-8 substitute for Ada.Strings.Maps is provided. The
implementation is enhanced in order to support sets defined by an indicator
function additionally to a set of ranges.
An equivalent to Ada.Strings.Maps.Constants is provided as well.
Unicode code points characterization into all categories defined by the
standard.
Blocks of Unicode characters as defined in the standard.
The license is as always GM GPL.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [relevance 6%]
* Re: STORAGE_ERROR : EXCEPTION_STACK_OVERFLOW
@ 2007-04-02 14:11 3% ` andrew.carroll
0 siblings, 0 replies; 35+ results
From: andrew.carroll @ 2007-04-02 14:11 UTC (permalink / raw)
All the files are below. The last file in the list, called
tables.txt, is the input file. I've supplied the input file I am
using when I get the errors.
with Ada.Text_IO, Ada.Directories, GNAT.Calendar.Time_IO,
Ada.Characters.Latin_1, Ada.IO_Exceptions,
Ada.Strings.Maps.Constants, Ada.Strings.Fixed,
Ada.Characters.Handling, Ada.Calendar,
schema_types, attribute_types, parser, util, index_types;
use parser, GNAT.Calendar.Time_IO, Ada.Characters.Latin_1,
Ada.Strings.Maps.Constants, Ada.Strings.Fixed,
Ada.Characters.Handling, Ada.Calendar, schema_types, attribute_types,
util;
procedure dbprog is
-- the input file contains the table specifications --
input : Ada.Text_IO.File_Type;
------------------------------------
-- Variables for Processing --
------------------------------------
char : Character;
line : string_ptr;
tablename : string_ptr;
datacols : string_array_ptr;
pkcols : string_array_ptr;
schemas : schema_array_ptr;
sindex : Integer := 1;
tupls : tuple_ptr;
procedure showoptionsmenu is
begin
cls;
pl ("---------------------------------------------------",
True);
pl ("Type one of the following at the prompt:", True);
pl (" ", True);
pl ("~ QUIT ", True);
pl ("1 INSERT DATA", True);
pl ("2 UPDATE DATA", True);
pl ("3 DELETE DATA", True);
pl ("4 SHOW RECORDS", True);
pl ("For help type 'help'", True);
pl ("---------------------------------------------------",
True);
pl (">>", False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
end showoptionsmenu;
function markschema return Integer is
idx : Integer := 0;
begin
--find the schema in schemas.
if schemas'length <= 0 then
return idx;
end if;
loop
idx := idx + 1;
exit when idx > schemas'length
or else Index (To_Upper (schemas
(idx).tablename), tablename.all) > 0;
end loop;
return idx;
end markschema;
procedure getcolumnnamesandvalues is
year : Year_Number;
month : Month_Number;
day : Day_Number;
line : string_ptr := new String'("");
valid : Boolean := False;
begin
--markschema sets sindex to the appropriate index in schemas
--for the table with tablename.
sindex := markschema;
--tables are already loaded and ready to go.
datacols := new string_array (1 .. schemas
(sindex).attributes'length);
for x in 1 .. schemas (sindex).attributes'length loop
if Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) = "DATE" then
while not valid loop
pl
("Enter a YEAR (1901 - 2099) for " &
Trim (schemas (sindex).attributes (x).name,
Ada.Strings.Both) &
" >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) > 0 then
pl ("!! INVALID !!", True, False);
elsif Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <= 0
and then Integer'value (line.all) not in
Ada.Calendar.Year_Number'range
then
pl ("!! INVALID !!", True, False);
else
valid := True;
end if;
end loop;
year := Year_Number'value (line.all);
valid := False;
while not valid loop
pl
("Enter a MONTH NUMBER for " &
Trim (schemas (sindex).attributes (x).name,
Ada.Strings.Both) &
" >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) > 0 then
pl ("!! INVALID !!", True, False);
elsif Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <= 0
and then Integer'value (line.all) not in
Ada.Calendar.Month_Number'range
then
pl ("!! INVALID !!", True, False);
else
valid := True;
end if;
end loop;
month := Month_Number'value (line.all);
valid := False;
while not valid loop
pl
("Enter a DAY NUMBER for " &
Trim (schemas (sindex).attributes (x).name,
Ada.Strings.Both) &
" >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) > 0 then
pl ("!! INVALID !!", True, False);
elsif Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <= 0
and then Integer'value (line.all) not in
Ada.Calendar.Day_Number'range
then
pl ("!! INVALID !!", True, False);
else
valid := True;
end if;
end loop;
day := Day_Number'value (line.all);
datacols.all (x) := new String'(Image (Time_Of (year,
month, day), ISO_Date));
valid := False;
else
while not valid loop
pl
("Enter a value for " &
Trim (schemas (sindex).attributes (x).name,
Ada.Strings.Both) &
"(" &
Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) &
") >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"BOOLEAN"
then
if To_Upper (line.all) = "TRUE" then
line := new String'("True");
valid := True;
elsif To_Upper (line.all) = "FALSE" then
line := new String'("False");
valid := True;
elsif line.all = "1" then
line := new String'("True");
valid := True;
elsif line.all = "0" then
line := new String'("False");
valid := True;
else
pl ("!! INVALID !!", True, False);
end if;
elsif Trim (schemas (sindex).attributes
(x).domain, Ada.Strings.Both) =
"INTEGER"
then
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <= 0 then
valid := True;
else
pl ("!! INVALID !!", True, False);
end if;
else --"STRING"
valid := True;
end if;
end loop;
valid := False;
datacols.all (x) := new String'(line.all);
end if;
end loop;
end getcolumnnamesandvalues;
procedure getprimarykeynamesandvalues is
year : Year_Number;
month : Month_Number;
day : Day_Number;
line : string_ptr := new String'("");
valid : Boolean := False;
begin
--markschema sets sindex to the appropriate index in schemas
--for the table with tablename.
sindex := markschema;
pl ("Provide the primary key values to identify the record to
delete.", False, True);
pl ("Press Enter to continue...", True, True);
Ada.Text_IO.Get_Immediate (char);
--tables are already loaded and ready to go.
pkcols := new string_array (1 .. schemas
(sindex).primary_key_count);
for x in 1 .. schemas (sindex).attributes'length loop
if schemas (sindex).attributes (x).isprimarykey then
if Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) = "DATE" then
while not valid loop
pl
("Enter a YEAR (1901 - 2099) for " &
Trim (schemas (sindex).attributes
(x).name, Ada.Strings.Both) &
" >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) > 0 then
pl ("!! INVALID !!", True, False);
elsif Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <= 0
and then Integer'value (line.all) not in
Ada.Calendar.Year_Number'range
then
pl ("!! INVALID !!", True, False);
else
valid := True;
end if;
end loop;
year := Year_Number'value (line.all);
valid := False;
while not valid loop
pl
("Enter a MONTH NUMBER for " &
Trim (schemas (sindex).attributes
(x).name, Ada.Strings.Both) &
" >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) > 0 then
pl ("!! INVALID !!", True, False);
elsif Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <= 0
and then Integer'value (line.all) not in
Ada.Calendar.Month_Number'
range
then
pl ("!! INVALID !!", True, False);
else
valid := True;
end if;
end loop;
month := Month_Number'value (line.all);
valid := False;
while not valid loop
pl
("Enter a DAY NUMBER for " &
Trim (schemas (sindex).attributes
(x).name, Ada.Strings.Both) &
" >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) > 0 then
pl ("!! INVALID !!", True, False);
elsif Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <= 0
and then Integer'value (line.all) not in
Ada.Calendar.Day_Number'range
then
pl ("!! INVALID !!", True, False);
else
valid := True;
end if;
end loop;
day := Day_Number'value (line.all);
pkcols.all (x) := new String'(Image (Time_Of
(year, month, day), ISO_Date));
valid := False;
else
while not valid loop
pl
("Enter a value for " &
Trim (schemas (sindex).attributes
(x).name, Ada.Strings.Both) &
"(" &
Trim (schemas (sindex).attributes
(x).domain, Ada.Strings.Both) &
") >>",
False,
False);
while Ada.Text_IO.End_Of_Line loop
Ada.Text_IO.Skip_Line;
end loop;
line := new String'(Ada.Text_IO.Get_Line);
if Trim (schemas (sindex).attributes
(x).domain, Ada.Strings.Both) =
"BOOLEAN"
then
if To_Upper (line.all) = "TRUE" then
line := new String'("True");
valid := True;
elsif To_Upper (line.all) = "FALSE" then
line := new String'("False");
valid := True;
elsif line.all = "1" then
line := new String'("True");
valid := True;
elsif line.all = "0" then
line := new String'("False");
valid := True;
else
pl ("!! INVALID !!", True, False);
end if;
elsif Trim (schemas (sindex).attributes
(x).domain, Ada.Strings.Both) =
"INTEGER"
then
if Index (line.all, Decimal_Digit_Set,
Ada.Strings.Outside) <=
0
then
valid := True;
else
pl ("!! INVALID !!", True, False);
end if;
else --"STRING"
valid := True;
end if;
end loop;
valid := False;
pkcols.all (x) := new String'(line.all);
end if;
end if;
end loop;
end getprimarykeynamesandvalues;
procedure gettablename is
count : Integer := 1;
begin
pl ("Enter the table name in CAPITAL letters >>", False);
tablename := new String'(Ada.Text_IO.Get_Line);
tablename.all := To_Upper (tablename.all);
while not Ada.Directories.Exists (tablename.all) and count < 5
loop
pl ("Enter the table name in CAPITAL letters >>", False);
tablename := new String'(Ada.Text_IO.Get_Line);
tablename.all := To_Upper (tablename.all);
count := count + 1;
end loop;
if count >= 5 then
raise Constraint_Error;
end if;
end gettablename;
procedure getchosenoptiondata is
begin
gettablename;
--we don't do "4" here because it is just a select and we
don't
--need values for it and we already have the attribute names
in
--the schemas(sindex) object for which to SELECT or SHOW the
--data.
if line.all = "1" then
getcolumnnamesandvalues;
elsif line.all = "2" then
getprimarykeynamesandvalues;
pl (" ", True, True);
pl ("Please enter new values for each item. You can enter
the same ", True, True);
pl ("data if you don't want it modified.", True, True);
pl (" ", True, True);
getcolumnnamesandvalues;
elsif line.all = "3" then
getprimarykeynamesandvalues;
end if;
end getchosenoptiondata;
procedure parsechosenoption is
pkattribs : attribute_array_ptr;
newvalues : attribute_array_ptr;
linelength : Integer;
outline : string_ptr;
begin
if line.all = "1" then
-------------------
-- INSERT DATA --
-------------------
newvalues := new attribute_array (1 .. schemas
(sindex).attributes'length);
--fill in the values on the objects and pass that to
insert.
for x in 1 .. newvalues'length loop
if Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"BOOLEAN"
then
newvalues (x) :=
new booleanattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Boolean'value (datacols
(x).all));
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"STRING"
then
newvalues (x) :=
new stringattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => max_stringlength * ' ');
Replace_Slice
(stringattribute (newvalues (x).all).value,
1,
max_stringlength,
datacols (x).all);
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"INTEGER"
then
newvalues (x) :=
new integerattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Integer'value (datacols
(x).all));
else -- "DATE"
newvalues (x) :=
new dateattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Value (datacols (x).all),
year => Year (Value (datacols
(x).all)),
month => Month (Value (datacols
(x).all)),
day => Day (Value (datacols
(x).all)));
end if;
end loop;
insertrec (schemas (sindex).all, newvalues.all);
elsif line.all = "2" then
-------------------
-- UPDATE DATA --
-------------------
pkattribs := new attribute_array (1 .. pkcols'length);
--fill in the values on the objects and pass that to
insert.
for x in 1 .. pkcols'length loop
if Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"BOOLEAN"
then
pkattribs (x) :=
new booleanattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Boolean'value (pkcols
(x).all));
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"STRING"
then
pkattribs (x) :=
new stringattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => max_stringlength * ' ');
Replace_Slice
(stringattribute (pkattribs (x).all).value,
1,
max_stringlength,
pkcols (x).all);
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"INTEGER"
then
pkattribs (x) :=
new integerattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Integer'value (pkcols
(x).all));
else -- "DATE"
pkattribs (x) :=
new dateattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Value (pkcols (x).all),
year => Year (Value (pkcols (x).all)),
month => Month (Value (pkcols
(x).all)),
day => Day (Value (pkcols (x).all)));
end if;
end loop;
newvalues := new attribute_array (1 .. schemas
(sindex).attributes'length);
--fill in the values on the objects and pass that to
insert.
for x in 1 .. newvalues'length loop
if Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"BOOLEAN"
then
newvalues (x) :=
new booleanattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Boolean'value (datacols
(x).all));
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"STRING"
then
newvalues (x) :=
new stringattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => max_stringlength * ' ');
Replace_Slice
(stringattribute (newvalues (x).all).value,
1,
max_stringlength,
datacols (x).all);
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"INTEGER"
then
newvalues (x) :=
new integerattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Integer'value (datacols
(x).all));
else -- "DATE"
newvalues (x) :=
new dateattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Value (datacols (x).all),
year => Year (Value (datacols
(x).all)),
month => Month (Value (datacols
(x).all)),
day => Day (Value (datacols
(x).all)));
end if;
end loop;
updaterec (schemas (sindex).all, pkattribs.all,
newvalues.all);
elsif line.all = "3" then
-------------------
-- DELETE DATA --
-------------------
Ada.Text_IO.Put_Line (Integer'image (sindex));
Ada.Text_IO.Put_Line (tablename.all);
pkattribs := new attribute_array (1 .. pkcols'length);
--fill in the values on the objects and pass that to
delete.
for x in 1 .. pkcols'length loop
if Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"BOOLEAN"
then
pkattribs (x) :=
new booleanattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Boolean'value (pkcols
(x).all));
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"STRING"
then
pkattribs (x) :=
new stringattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => max_stringlength * ' ');
Replace_Slice
(stringattribute (pkattribs (x).all).value,
1,
max_stringlength,
pkcols (x).all);
elsif Trim (schemas (sindex).attributes (x).domain,
Ada.Strings.Both) =
"INTEGER"
then
pkattribs (x) :=
new integerattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Integer'value (pkcols
(x).all));
else -- "DATE"
pkattribs (x) :=
new dateattribute'
(name => schemas (sindex).attributes
(x).name,
domain => schemas (sindex).attributes
(x).domain,
isprimarykey => schemas (sindex).attributes
(x).isprimarykey,
byte_start => 0,
byte_end => 0,
value => Value (pkcols (x).all),
year => Year (Value (pkcols (x).all)),
month => Month (Value (pkcols
(x).all)),
day => Day (Value (pkcols (x).all)));
end if;
end loop;
deleterec (schemas (sindex).all, pkattribs.all);
elsif line.all = "4" then
----------------------
-- SELECT RECORDS --
----------------------
linelength := 60;
sindex := markschema;
outline := new String'(1 .. linelength => '-');
pl (outline.all, True, False);
pl (schemas (sindex).tablename, True, False);
pl (outline.all, True, False);
pl ("| ", False, False);
for x in 1 .. schemas (sindex).attributes'length loop
pl (Trim (schemas (sindex).attributes (x).name,
Ada.Strings.Both), False, False);
if x < schemas (sindex).attributes'length then
pl (" | ", False, False);
end if;
end loop;
pl (" |", True, False);
pl (outline.all, True, False);
tupls := selectrec (schemas (sindex).all);
if tupls = null then
pl ("No Data", True, False);
else
for y in 1 .. tupls'length loop
newvalues := tupls (y);
for x in 1 .. newvalues'length loop
if Trim (newvalues (x).domain,
Ada.Strings.Both) = "BOOLEAN" then
pl
(Trim
(Boolean'image (booleanattribute
(newvalues (x).all).value),
Ada.Strings.Both),
False,
False);
elsif Trim (newvalues (x).domain,
Ada.Strings.Both) = "STRING" then
pl
(Trim
(stringattribute (newvalues
(x).all).value,
Ada.Strings.Both),
False,
False);
elsif Trim (newvalues (x).domain,
Ada.Strings.Both) = "INTEGER" then
pl
(Trim
(Integer'image (integerattribute
(newvalues (x).all).value),
Ada.Strings.Both),
False,
False);
else -- "DATE"
pl
(Trim
(Image (dateattribute (newvalues
(x).all).value, ISO_Date),
Ada.Strings.Both),
False,
False);
end if;
if x < newvalues'length then
pl (" ", False, False);
end if;
end loop;
pl (" ", True, False);
end loop;
end if;
pl (outline.all, True, False);
pl ("Press Enter >>", False, False);
Ada.Text_IO.Get_Immediate (char);
end if;
sindex := 0;
tablename := null;
datacols := null;
pkcols := null;
tupls := null;
end parsechosenoption;
begin
cls;
pl ("---------------------------------------------------", True);
pl ("Put your table definitions in a file named ", True);
pl ("tables.txt and place the file in the same folder as", True);
pl ("this program (Parser.exe). Type C to continue or.", True);
pl ("~ to quit.", True);
pl ("---------------------------------------------------", True);
pl (">>", False);
Ada.Text_IO.Get (char);
line := new String'(Ada.Text_IO.Get_Line);
if char = ETX or char = Tilde then
raise Ada.IO_Exceptions.End_Error;
end if;
setinputfile ("tables.txt");
schemas := parsetables;
closeinputfile;
showoptionsmenu;
while line.all /= "~" loop
if line.all = "help" or line.all = "HELP" then
pl ("---------------------------------------------------",
True);
pl ("If you want to quit type the tilde '~' character",
True);
pl ("---------------------------------------------------",
True);
pl (">>", False);
line := new String'(Ada.Text_IO.Get_Line);
cls;
elsif line.all = "goodbye" or
line.all = "GOODBYE" or
line.all = "exit" or
line.all = "EXIT" or
line.all = "quit" or
line.all = "QUIT" or
line.all = "q" or
line.all = "Q"
then
line := new String'("~");
else
------------------------
-- output results --
------------------------
getchosenoptiondata;
parsechosenoption;
showoptionsmenu;
end if;
end loop;
cls;
pl ("---------------------------------------------------", True);
pl ("Goodbye!", True);
pl ("---------------------------------------------------", True);
exception
when Ada.IO_Exceptions.End_Error =>
if Ada.Text_IO.Is_Open (input) then
Ada.Text_IO.Close (input);
end if;
cls;
pl ("---------------------------------------------------",
True);
pl ("An error occured while reading data. Possibly a
missing", True);
pl ("semi-colon or other format character. Or, you pressed ",
True);
pl ("CTRL + C. Goodbye!", True);
pl ("---------------------------------------------------",
True);
when Ada.Calendar.Time_Error =>
pl ("A date value was not entered correctly.", True);
pl ("Unfortunately this will cause the program to exit.",
True);
pl ("Your data is safe so long as you don't 'create fresh'.",
True);
pl ("the table when you start the program again.", True);
when Ada.IO_Exceptions.Data_Error =>
if Ada.Text_IO.Is_Open (input) then
Ada.Text_IO.Close (input);
end if;
when Constraint_Error =>
Ada.Text_IO.Put_Line ("You entered the data wrong.");
end dbprog;
with Ada.Text_IO, schema_types, attribute_types;
use schema_types, attribute_types;
package parser is
file : Ada.Text_IO.File_Type;
---------------------------
-- Utility Methods --
---------------------------
procedure setinputfile (filename : String);
procedure closeinputfile;
function parsetables return schema_array_ptr;
function parsetable return schema'class;
function parseattributes return attribute_array_ptr;
function parseattribute return attribute'class;
end parser;
with Ada.Text_IO, Ada.Directories, Ada.Integer_Text_IO,
Ada.Strings.Fixed, Ada.Characters.Latin_1,
Ada.IO_Exceptions, schema_types, attribute_types, util;
use Ada.Strings.Fixed, Ada.Characters.Latin_1, schema_types,
attribute_types, util;
package body parser is
procedure setinputfile (filename : String) is
begin
Ada.Text_IO.Open (file, Ada.Text_IO.In_File, filename);
end setinputfile;
procedure closeinputfile is
begin
if Ada.Text_IO.Is_Open (file) then
Ada.Text_IO.Close (file);
end if;
end closeinputfile;
-----------------------
-- parseTables --
-----------------------
function parsetables return schema_array_ptr is
eof : Boolean := False;
char : Character;
schemas : schema_array_ptr := null;
swap : schema_array_ptr := null;
schemainfo : schema_ptr := null;
i : Integer := 1;
begin
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
--at this point we should be ready to read the table name.
swap := new schema_array (1 .. max_tables);
while not eof loop
schemainfo := new schema'class'(parsetable);
pl ("Create the table fresh? [y/Y] >>", False, True);
Ada.Text_IO.Get (char);
swap(i) := new schema(schemainfo.attributes'length);
if char = 'y' or char = 'Y' then
swap (i) := schemainfo;
createtable (swap (i));
else
if Ada.Directories.Exists (schemainfo.tablename) then
swap (i) := loadtable (schemainfo.tablename);
else
pl ("No table exists on disc with name = " &
schemainfo.tablename, True, True);
pl ("You will not be able to query " &
schemainfo.tablename, True, True);
pl (" ", True, False);
end if;
end if;
i := i + 1;
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
end if;
end loop;
i := i - 1;
if i < 1 then
schemas := null;
swap := null;
else
schemas := new schema_array (1 .. i);
for x in 1 .. i loop
schemas (x) := swap (x);
end loop;
swap := null;
end if;
return schemas;
end parsetables;
----------------------
-- parseTable --
----------------------
function parsetable return schema'class is
temp : schema_ptr := null;
eof : Boolean := False;
char : Character;
tname : String (1 .. max_tablename_length);
attribs : attribute_array_ptr;
i : Integer := 1;
begin
eatWhite (file, eof);
--at this point we should be ready to read the table name.
--the call to eatwhite might be redundant from the instance
that
--called 'me' but we want to ensure we are in the right
location within
--the file.
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
while char /= Space and
char /= HT and
char /= LF and
char /= CR and
char /= Left_Parenthesis and
not eof
loop
Ada.Text_IO.Get (file, char);
tname (i) := char;
i := i + 1;
Ada.Text_IO.Look_Ahead (file, char, eof);
end loop;
for x in i .. max_tablename_length loop
tname (x) := ' ';
end loop;
--We just read the table name. We are expecting an opening
'('.
--If it's not there then there is a problem with the input
file
--format.
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
if char = Left_Parenthesis then
Ada.Text_IO.Get (file, char);
else
Ada.Text_IO.Put_Line(
" Error in input file format: No attributes found. Must have
(<attribute list>)");
end if;
else
raise Ada.IO_Exceptions.End_Error;
end if;
attribs := parseattributes;
if attribs /= null then
temp := new schema (attribs.all'length);
temp.attributes := attribs.all;
temp.tablename := tname;
for x in 1 .. temp.attributes'length loop
if temp.attributes (x).all.isprimarykey then
temp.primary_key_count := temp.primary_key_count +
1;
end if;
end loop;
else
temp := null;
end if;
--at this point we should have read the ')' for the whole
table spec.
--if we peek, we should find a ';'.
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
if char = Semicolon then
Ada.Text_IO.Get (file, char);
else
Ada.Text_IO.Put_Line
(" Error in input file format: Missing
closing ';' on table spec.");
temp := null;
end if;
else
Ada.Text_IO.Put_Line
(" Error in input file format: Missing closing
')' on table spec.");
temp := null;
end if;
return temp.all;
end parsetable;
---------------------------
-- parseAttributes --
---------------------------
function parseattributes return attribute_array_ptr is
eof : Boolean := False;
char : Character;
attribs : attribute_array_ptr := null;
swap : attribute_array_ptr := null;
i : Integer := 1;
begin
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
--at this point we should be ready to read the attribute name.
if not eof and char /= Right_Parenthesis then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
Ada.Text_IO.Put_Line (" found eof prematurely
or ')' is in wrong place.");
raise Ada.IO_Exceptions.End_Error;
end if;
swap := new attribute_array (1 .. max_columns);
while char /= Right_Parenthesis and char /= Semicolon and not
eof loop
swap (i) := new attribute'class'(parseattribute);
i := i + 1;
eatWhite (file, eof);
if not eof and char /= Right_Parenthesis then
--we are expecting a ')' or a comma.
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
if char /= Comma and char /= Right_Parenthesis and not eof
then
Ada.Text_IO.Put_Line
(" Error in input file: Missing comma
between attributes.");
eof := True;
swap := null;
elsif not eof then
--read the comma or the ')'
Ada.Text_IO.Get (file, char);
end if;
eatWhite (file, eof);
if eof then
Ada.Text_IO.Put_Line ("Missing semi-colon or other
format error.");
raise Ada.IO_Exceptions.End_Error;
end if;
end loop;
i := i - 1;
if i < 1 then
swap := null;
else
attribs := new attribute_array (1 .. i);
for x in 1 .. i loop
attribs (x) := swap (x);
end loop;
swap := null;
end if;
return attribs;
end parseattributes;
--------------------------
-- parseAttribute --
--------------------------
function parseattribute return attribute'class is
temp : attribute_types.attribute_ptr;
eof : Boolean := False;
char : Character;
aname : String (1 .. max_attributename_length);
atype : String (1 .. max_typename_length);
asize : Integer;
isprimarykey : Boolean := False;
i : Integer := 1;
begin
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
while char /= Space and
char /= HT and
char /= LF and
char /= CR and
char /= Left_Parenthesis and
char /= Colon and
not eof
loop
Ada.Text_IO.Get (file, char);
aname (i) := char;
i := i + 1;
Ada.Text_IO.Look_Ahead (file, char, eof);
end loop;
for x in i .. max_attributename_length loop
aname (x) := ' ';
end loop;
--at this point we have the attribute name. Read white space
to
--a parenthesis or an colon.
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
--the next character should be '(' or ':'
if char = Left_Parenthesis then
Ada.Text_IO.Get (file, char);
eatWhite (file, eof);
i := 1;
--read "primary"
while char /= Space and
char /= HT and
char /= LF and
char /= CR and
char /= Right_Parenthesis and
not eof
loop
Ada.Text_IO.Get (file, char);
atype (i) := char;
i := i + 1;
Ada.Text_IO.Look_Ahead (file, char, eof);
end loop;
for x in i .. max_typename_length loop
atype (x) := ' ';
end loop;
if Trim (atype, Ada.Strings.Both) = "PRIMARY" then
isprimarykey := True;
end if;
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
i := 1;
--read "key"
while char /= Space and
char /= HT and
char /= LF and
char /= CR and
char /= Right_Parenthesis and
not eof
loop
Ada.Text_IO.Get (file, char);
atype (i) := char;
i := i + 1;
Ada.Text_IO.Look_Ahead (file, char, eof);
end loop;
for x in i .. max_typename_length loop
atype (x) := ' ';
end loop;
if Trim (atype, Ada.Strings.Both) = "KEY" then
isprimarykey := True;
else
isprimarykey := False;
end if;
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
if char = ')' then
Ada.Text_IO.Get (file, char);
else
Ada.Text_IO.Put_Line
(" Error in input: Missing ')' after
Primary Key designation.");
end if;
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
end if;
if char = Colon then
Ada.Text_IO.Get (file, char);
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
i := 1;
--read the type of the attribute into atype variable
while char /= Space and
char /= HT and
char /= LF and
char /= CR and
char /= Comma and
char /= Left_Parenthesis and
char /= Right_Parenthesis and
char /= Semicolon and
not eof
loop
Ada.Text_IO.Get (file, char);
atype (i) := char;
i := i + 1;
Ada.Text_IO.Look_Ahead (file, char, eof);
end loop;
for x in i .. max_typename_length loop
atype (x) := ' ';
end loop;
eatWhite (file, eof);
--read the left parenthesis
if not eof and
char = Left_Parenthesis and
Trim (atype, Ada.Strings.Both) = "STRING"
then
Ada.Text_IO.Get (file, char);
Ada.Text_IO.Look_Ahead (file, char, eof);
elsif not eof and
char /= Left_Parenthesis and
Trim (atype, Ada.Strings.Both) = "STRING"
then
Ada.Text_IO.Put_Line (" Incorrect syntax:
missing (size) for string.");
elsif eof then
raise Ada.IO_Exceptions.End_Error;
end if;
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
--read the size of the type of the attribute into atype
variable
while char /= Space and
char /= HT and
char /= LF and
char /= CR and
char /= Comma and
char /= Right_Parenthesis and
char /= Left_Parenthesis and
not eof
loop
Ada.Integer_Text_IO.Get (file, asize, 0);
Ada.Text_IO.Look_Ahead (file, char, eof);
end loop;
--I have to do this temporarily to get this program
--to work. ALL strings are the same length. The reason
--is because there is no way to know how long the string
is
--when serializing it in from a file (see loadtable in
--schema_types) before we serialize it so that we can
--provide a length discriminant to the type defined in
--attribute_types. So, we just make them all the same
--length.
asize := max_stringlength;
eatWhite (file, eof);
--read the right parenthesis
if not eof and
char = Right_Parenthesis and
Trim (atype, Ada.Strings.Both) = "STRING"
then
Ada.Text_IO.Get (file, char);
Ada.Text_IO.Look_Ahead (file, char, eof);
elsif not eof and
char /= Right_Parenthesis and
Trim (atype, Ada.Strings.Both) = "STRING"
then
Ada.Text_IO.Put_Line
(" Incorrect syntax: missing (size ~)~
for string.");
elsif eof then
raise Ada.IO_Exceptions.End_Error;
end if;
eatWhite (file, eof);
if Trim (atype, Ada.Strings.Both) = "BOOLEAN" then
temp := new booleanattribute;
temp.name := aname;
temp.domain := atype;
if isprimarykey then
temp.isprimarykey := True;
end if;
elsif Trim (atype, Ada.Strings.Both) = "STRING" then
temp := new stringattribute;
temp.name := aname;
temp.domain := atype;
if isprimarykey then
temp.isprimarykey := True;
end if;
elsif Trim (atype, Ada.Strings.Both) = "INTEGER" then
temp := new integerattribute;
temp.name := aname;
temp.domain := atype;
if isprimarykey then
temp.isprimarykey := True;
end if;
elsif Trim (atype, Ada.Strings.Both) = "DATE" then
temp := new dateattribute;
temp.name := aname;
temp.domain := atype;
if isprimarykey then
temp.isprimarykey := True;
end if;
else
Ada.Text_IO.Put_Line (" unknown type
specified.");
end if;
--after eating the white space we should be left at the
',' or
--the ')'.
eatWhite (file, eof);
if not eof then
Ada.Text_IO.Look_Ahead (file, char, eof);
else
raise Ada.IO_Exceptions.End_Error;
end if;
--we leave the comma in the stream so that parseAttributes
can
--pick it up and loop for the next attribute. We leave
the second
--')' for parseAttributes to read to know when to exit the
loop and
--quit parsing attributes.
if char /= Comma and char /= Right_Parenthesis then
Ada.Text_IO.Put_Line(
" Error in input: Missing ')' after Primary Key
designation or ',' between attributes.")
;
temp := null;
end if;
else
Ada.Text_IO.Put_Line
(
" Error in input file: Format not correct, no type
specified for attribute " &
aname);
temp := null;
end if;
return temp.all;
end parseattribute;
begin
null;
end parser;
with Ada.Text_IO, Ada.Characters.Latin_1, Ada.Strings.Fixed,
Ada.Strings.Maps, Ada.IO_Exceptions;
use Ada.Characters.Latin_1;
package util is
type string_ptr is access all String;
type string_array is array (Integer range <>) of string_ptr;
type string_array_ptr is access all string_array;
max_columns : Integer := 5;
max_tables : Integer := 5;
max_tablename_length : Integer := 25;
max_attributename_length : Integer := 25;
max_stringlength : Integer := 255;
max_typename_length : Integer := 7;
max_filename_length : Integer := 45;
max_index_namelength: integer := 50;
procedure cls;
procedure pl (text : in String; newline : in Boolean; setcolumn :
in Boolean := True);
function tokenize (text : in String) return string_array_ptr;
procedure eatWhite (fin : in out Ada.Text_IO.File_Type; eof : in
out Boolean);
end util;
package body Util is
procedure cls is
i : Integer := 1;
begin
while i < 40 loop
Ada.Text_IO.New_Line;
i := i + 1;
end loop;
end cls;
procedure pl (text : in String; newline : in Boolean; setcolumn :
in Boolean := True) is
begin
if newline then
if setcolumn then
Ada.Text_IO.Set_Col (15);
end if;
Ada.Text_IO.Put_Line (text);
elsif setcolumn then
Ada.Text_IO.Set_Col (15);
Ada.Text_IO.Put (text);
else
Ada.Text_IO.Put (text);
end if;
end pl;
function tokenize (text : in String) return string_array_ptr is
temp : string_array_ptr;
first : Integer := 1;
i : Integer := 1;
number_of_commas : Integer := 0;
data : string_ptr;
data2 : string_ptr;
begin
data := new String'(text);
number_of_commas := Ada.Strings.Fixed.Count (data.all,
Ada.Strings.Maps.To_Set (','));
if number_of_commas > max_columns then
pl ("Invalid number of columns specified", True);
raise Ada.IO_Exceptions.Data_Error;
end if;
temp := new string_array (1 .. number_of_commas + 1);
--first will point to the first comma.
first :=
Ada.Strings.Fixed.Index
(data.all,
Ada.Strings.Maps.To_Set (','),
Ada.Strings.Inside,
Ada.Strings.Forward);
while i <= number_of_commas and number_of_commas < max_columns
loop
temp.all (i) := new String'(data.all (1 .. first - 1));
data2 := new String (1 .. data.all'length - first);
data2.all := data.all (first + 1 .. data.all'length);
data := new String'(data2.all);
i := i + 1;
first :=
Ada.Strings.Fixed.Index
(data.all,
Ada.Strings.Maps.To_Set (','),
Ada.Strings.Inside,
Ada.Strings.Forward);
end loop;
temp.all (i) := new String'(data.all);
return temp;
end tokenize;
--------------------
-- eatWhite --
--------------------
procedure eatWhite (fin : in out Ada.Text_IO.File_Type; eof : in
out Boolean) is
char : Character;
begin
Ada.Text_IO.Look_Ahead (fin, char, eof);
while Ada.Text_IO.End_Of_Line (fin) and not
Ada.Text_IO.End_Of_File (fin) loop
Ada.Text_IO.Skip_Line (fin);
end loop;
Ada.Text_IO.Look_Ahead (fin, char, eof);
while (char = Space or char = HT or char = LF or char = CR)
and
not Ada.Text_IO.End_Of_File (fin)
loop
Ada.Text_IO.Get (fin, char);
while Ada.Text_IO.End_Of_Line (fin) and not
Ada.Text_IO.End_Of_File (fin) loop
Ada.Text_IO.Skip_Line (fin);
end loop;
Ada.Text_IO.Look_Ahead (fin, char, eof);
end loop;
end eatWhite;
begin
null;
end Util;
with util, Ada.Calendar, attribute_types, Ada.Streams.Stream_IO;
use util, attribute_types;
package schema_types is
---------------------------------
-- Variable Declarations --
---------------------------------
fin : Ada.Streams.Stream_IO.File_Type;
fout : Ada.Streams.Stream_IO.File_Type;
type schema (number_of_attributes : Integer) is tagged record
tablename : String (1 .. max_tablename_length) := (1 ..
max_tablename_length => ' ');
attributes : attribute_array (1 ..
number_of_attributes);
byte_start : Integer := 0;
byte_end : Integer := 0;
primary_key_count : Integer := 0;
end record;
type schema_ptr is access all schema'class;
type schema_array is array (Integer range <>) of schema_ptr;
type schema_array_ptr is access all schema_array;
type tuple is array (Integer range <>) of attribute_array_ptr;
type tuple_ptr is access all tuple;
procedure createtable (schemainfo : schema_ptr);
function loadtable (sname : String) return schema_ptr;
function findrecord (schemainfo : schema; values :
attribute_array) return Integer;
procedure insertrec (schemainfo : schema; values :
attribute_array);
procedure deleterec (schemainfo : schema; primary_key_values :
attribute_array);
procedure updaterec
(schemainfo : schema;
pkattribs : attribute_array;
values : attribute_array);
function selectrec (schemainfo : schema) return tuple_ptr;
end schema_types;
with Ada.Streams.Stream_IO, Ada.Calendar, GNAT.Calendar.Time_IO,
Ada.Text_IO, Ada.Strings.Fixed,
Ada.Directories, Ada.IO_Exceptions;
use Ada.Streams.Stream_IO, Ada.Calendar, GNAT.Calendar.Time_IO,
Ada.Strings.Fixed;
package body schema_types is
procedure createtable (schemainfo : schema_ptr) is
fout : File_Type;
attribs : attribute_array_ptr;
attribs2 : attribute_array_ptr;
i : Integer := 1;
ii : Integer := 1;
temp : access attribute'class;
begin
if schemainfo = null then
return;
end if;
-- put them in order first
for x in 1 .. schemainfo.attributes'length loop
for y in x + 1 .. schemainfo.attributes'length loop
if schemainfo.attributes (y).name <
schemainfo.attributes (x).name then
temp := schemainfo.attributes
(y);
schemainfo.attributes (y) := schemainfo.attributes
(x);
schemainfo.attributes (x).all := temp.all;
end if;
end loop;
end loop;
attribs := new attribute_array (1 ..
schemainfo.attributes'length);
attribs2 := new attribute_array (1 ..
schemainfo.attributes'length);
for x in 1 .. schemainfo.attributes'length loop
if schemainfo.attributes (x).isprimarykey then
attribs (i) := schemainfo.attributes (x);
i := i + 1;
else
attribs2 (ii) := schemainfo.attributes (x);
ii := ii + 1;
end if;
end loop;
i := i - 1;
ii := ii - 1;
-- the primary_key attributes first
for x in 1 .. i loop
schemainfo.attributes (x) := attribs (x);
end loop;
-- non-primary key attributes next
for x in 1 .. ii loop
schemainfo.attributes (x + i) := attribs2 (x);
end loop;
Create (fout, Out_File, Trim (schemainfo.all.tablename,
Ada.Strings.Both));
--We are writing the number of attributes so that when we load
--the table we can determine the number of attributes to put
--into the new, loading schema.
Integer'write (Stream (fout),
schemainfo.all.attributes'length);
schemainfo.all.byte_start := Integer'val (Index (fout));
--we output it once so that we can capture the file position for
byte_end
schema'output (Stream (fout), schemainfo.all);
--fill in byte_end
schemainfo.all.byte_end := Integer'val (Index (fout));
close(fout);
Open (fout, Out_File, Trim (schemainfo.all.tablename,
Ada.Strings.Both));
Integer'write (Stream (fout),
schemainfo.all.attributes'length);
--now we have byte_start and byte_end
schema'output (Stream (fout), schemainfo.all);
for x in 1 .. schemainfo.all.attributes'length loop
to_disc(fout, schemainfo.all.attributes(x).all);
end loop;
Close (fout);
end createtable;
function loadtable (sname : String) return schema_ptr is
schemainfo : schema_ptr;
fin : File_Type;
length : Integer;
position : integer;
begin
Open (fin, In_File, Trim (sname, Ada.Strings.Both));
Integer'read (Stream (fin), length);
schemainfo := new schema (length);
schemainfo.all := schema'class'input (Stream
(fin));
--mark where we are at in the file to start reading attributes.
position := Integer'val (Index (fin));
for x in 1 .. schemainfo.attributes'length loop
-----------------------------------------------------
-- Old code I plan on removing
-----------------------------------------------------
-- schemainfo.all.attributes (x).all.byte_start :=
position;
--
-- if Trim (schemainfo.all.attributes (x).domain,
Ada.Strings.Both) = "BOOLEAN" then
-- schemainfo.all.attributes (x) := new
booleanattribute;
-- schemainfo.all.attributes (x).all :=
-- booleanattribute'input (Stream (fin));
-- elsif Trim (schemainfo.all.attributes (x).domain,
Ada.Strings.Both) = "STRING" then
-- schemainfo.all.attributes (x) :=
new stringattribute;
-- schemainfo.all.attributes (x).all :=
-- stringattribute'input (Stream (fin));
-- elsif Trim (schemainfo.all.attributes (x).domain,
Ada.Strings.Both) = "INTEGER" then
-- schemainfo.all.attributes (x) :=
new integerattribute;
-- schemainfo.all.attributes (x).all :=
-- integerattribute'input (Stream (fin));
-- else -- "DATE"
-- schemainfo.all.attributes (x) :=
new dateattribute;
-- schemainfo.all.attributes (x).all :=
-- dateattribute'input (Stream (fin));
-- end if;
-- position := Integer'val (Index (fin));
-- schemainfo.all.attributes (x).all.byte_end :=
position;
-- End old code
------------------------------------------------------
-----------------------------------------------------------
-- The code I want to use for dispatching
-----------------------------------------------------------
-- schemainfo.all.attributes (x) := new
attribute'class'(from_disc(fin, schemainfo.all.attributes (x).all));
-----------------------------------------------------------
------------------------------------------------------------
-- Debug code below --
------------------------------------------------------------
-- For some reason some of the attributes on schemainfo come through
-- as "unknown" after the schemainfo was filled in from
'input(stream).
-- It doesn't appear to me that createtable procedure in this package
-- writes the schema object incorrectly so I don't understand why
-- the attributes of the schemainfo object we retrieve with 'input are
-- "unknown". Well, the domain member of the attribute is not one of
-- BOOLEAN, STRING, INTEGER or DATE; that's why it prints it but why
-- isn't the domain member one of those values?
if Trim (schemainfo.all.attributes (x).domain,
Ada.Strings.Both) = "BOOLEAN" then
ada.text_io.put_line(schemainfo.all.attributes (x).name);
ada.text_io.put_line(schemainfo.all.attributes (x).domain);
elsif Trim (schemainfo.all.attributes (x).domain,
Ada.Strings.Both) = "STRING" then
ada.text_io.put_line(schemainfo.all.attributes (x).name);
ada.text_io.put_line(schemainfo.all.attributes (x).domain);
elsif Trim (schemainfo.all.attributes (x).domain,
Ada.Strings.Both) = "INTEGER" then
ada.text_io.put_line(schemainfo.all.attributes (x).name);
ada.text_io.put_line(schemainfo.all.attributes (x).domain);
elsif Trim (schemainfo.all.attributes (x).domain,
Ada.Strings.Both) = "DATE" then
ada.text_io.put_line(schemainfo.all.attributes (x).name);
ada.text_io.put_line(schemainfo.all.attributes (x).domain);
else
ada.text_io.put_line("unknown");
end if;
end loop;
-- End Debug Code
---------------------------------------------------------------
Close (fin);
return schemainfo;
exception
when Ada.IO_Exceptions.Status_Error =>
Ada.Text_IO.Put_Line ("Status error in loadtable");
return null;
end loadtable;
---------------------
-- INSERT RECORD --
---------------------
procedure insertrec (schemainfo : schema; values :
attribute_array) is
location : Integer := -1;
char : Character;
begin
location := findrecord (schemainfo, values);
--if the record isn't in there it is -1
if location = -1 then
Open (fout, Append_File, Trim (schemainfo.tablename,
Ada.Strings.Both));
for x in 1 .. schemainfo.attributes'length loop
to_disc(fout, values (x).all);
end loop;
Close (fout);
else
pl ("Record already exists with that key", True, True);
pl ("Press Enter to continue...", True, True);
Ada.Text_IO.Get_Immediate (char);
end if;
end insertrec;
---------------------
-- SELECT RECORD --
---------------------
function selectrec (schemainfo : schema) return tuple_ptr is
temp : attribute_array_ptr;
recs : tuple_ptr;
recs2 : tuple_ptr;
i : Integer := 1;
begin
Open (fin, In_File, Trim (schemainfo.tablename,
Ada.Strings.Both));
Set_Index
(fin,
Ada.Streams.Stream_IO.Count'val
(schemainfo.attributes
(schemainfo.attributes'length).all.byte_end));
temp := new attribute_array (1 ..
schemainfo.attributes'length);
if End_Of_File (fin) then
Close (fin);
return null;
end if;
recs := new tuple (1 .. 1);
while not End_Of_File (fin) loop
for x in 1 .. temp.all'length loop
temp(x) := new attribute'class'(from_disc(fin, schemainfo.attributes
(x).all));
end loop;
if i < 2 then
recs (recs'last) := temp;
else
recs2 := new tuple (1 .. recs'length);
for z in 1 .. recs'length loop
recs2 (z) := recs (z);
end loop;
recs := new tuple (1 .. i);
for z in 1 .. recs2'length loop
recs (z) := recs2 (z);
end loop;
recs (recs'last) := temp;
end if;
temp := new attribute_array (1 ..
schemainfo.attributes'length);
i := i + 1;
end loop;
Close (fin);
return recs;
end selectrec;
-------------------
-- FIND RECORD --
-------------------
function findrecord (schemainfo : schema; values :
attribute_array) return Integer is
temp : attribute_array_ptr;
location : Ada.Streams.Stream_IO.Count;
found : Integer := 0;
done : Boolean := False;
comparrisons : Integer := 0;
begin
Open (fin, In_File, Trim (schemainfo.tablename,
Ada.Strings.Both));
Set_Index
(fin,
Ada.Streams.Stream_IO.Count'val
(schemainfo.attributes
(schemainfo.attributes'length).all.byte_end));
temp := new attribute_array (1 ..
schemainfo.attributes'length);
while not End_Of_File (fin) and then not done loop
--mark our current location in the file.
location := Index (fin);
--read the whole line from the file,
for x in 1 .. schemainfo.attributes'length loop
temp(x) := new attribute'class'(from_disc(fin,
schemainfo.attributes(x).all));
end loop;
--then compare them.
comparrisons := 0;
found := 0;
for x in 1 .. values'length loop
if schemainfo.attributes (x).isprimarykey then
comparrisons := comparrisons + 1;
if Trim (values (x).domain, Ada.Strings.Both) =
"BOOLEAN" then
if booleanattribute (temp (x).all).value =
booleanattribute (values (x).all).value
then
found := found + 1;
end if;
--
ada.text_io.put_line(boolean'image(booleanattribute(temp(x).all).value
--));
elsif Trim (values (x).domain, Ada.Strings.Both) =
"STRING" then
if stringattribute (temp (x).all).value =
stringattribute (values (x).all).value
then
found := found + 1;
end if;
--
ada.text_io.put_line(stringattribute(temp(x).all).value);
elsif Trim (values (x).domain, Ada.Strings.Both) =
"INTEGER" then
if integerattribute (temp (x).all).value =
integerattribute (values (x).all).value
then
found := found + 1;
end if;
--
ada.text_io.put_line(integer'image(integerattribute(temp(x).all).value
--));
else -- "DATE"
if dateattribute (temp (x).all).value =
dateattribute (values (x).all).value
then
found := found + 1;
end if;
--
ada.text_io.put_line(image(dateattribute(temp(x).all).value,
--iso_date));
end if;
end if;
end loop;
if found = comparrisons and then comparrisons > 0 then
done := True;
end if;
if End_Of_File (fin) then
done := True;
end if;
end loop;
Close (fin);
if found < comparrisons then
return -1;
elsif found = 0 and then comparrisons = 0 then
return -1;
else
return Integer'val (location);
end if;
end findrecord;
---------------------
-- DELETE RECORD --
---------------------
procedure deleterec (schemainfo : schema; primary_key_values :
attribute_array) is
location : Integer;
original_byte_end : Integer := schemainfo.attributes
(schemainfo.attributes'last).byte_end;
temp : attribute_array_ptr;
char : Character;
begin
location := findrecord (schemainfo, primary_key_values);
--If findrecord seeks past the schema info header in the file
and ends
--on the end of file it will return -1. Therefore, no records
to delete
--in the file.
if location = -1 then
pl ("No records to delete with that key", True, True);
pl ("Press Enter to continue...", True, True);
Ada.Text_IO.Get_Immediate (char);
return;
end if;
Create (fout, Out_File, "swapfile");
Open (fin, In_File, Trim (schemainfo.tablename,
Ada.Strings.Both));
--output the schema header information to the file
Integer'write (Stream (fout), schemainfo.attributes'length);
--I took these out so that we could create a function for
--updating records that returns an rrn. functions do not
--allow out mode parameters and deleterec had an out mode
--parameter because of this next line.
--schemainfo.byte_start := Integer'val (Index (fout));
schema'output (Stream (fout), schemainfo);
--I took these out so that we could create a function for
--updating records that returns an rrn. functions do not
--allow out mode parameters and deleterec had an out mode
--parameter because of this next line.
--schemainfo.byte_end := Integer'val (Index (fout));
for x in 1 .. schemainfo.attributes'length loop
to_disc(fout, schemainfo.attributes(x).all);
end loop;
--set the index on the input file so we skip the header on
input file.
Set_Index (fin, Ada.Streams.Stream_IO.Count'val
(original_byte_end));
temp := new attribute_array (1 ..
schemainfo.attributes'length);
--Read records from one file and insert them into the other
file until
--we get to the location of the record we want to delete.
while Index (fin) < Ada.Streams.Stream_IO.Count'val (location)
loop
for x in 1 .. temp.all'length loop
temp(x) := new attribute'class'(from_disc(fin,
schemainfo.attributes(x).all));
to_disc(fin, temp(x).all);
end loop;
end loop;
--do a blank read to move past the line to delete
for x in 1 .. schemainfo.attributes'length loop
temp(x) := new attribute'class'(from_disc(fin,
schemainfo.attributes(x).all));
end loop;
--output the rest of the records.
while not End_Of_File (fin) loop
for x in 1 .. temp.all'length loop
temp(x) := new attribute'class'(from_disc(fin,
schemainfo.attributes(x).all));
to_disc(fout, temp(x).all);
end loop;
end loop;
Close (fin);
Close (fout);
Ada.Directories.Delete_File (Trim (schemainfo.tablename,
Ada.Strings.Both));
Ada.Directories.Rename ("swapfile", Trim
(schemainfo.tablename, Ada.Strings.Both));
location := findrecord (schemainfo, primary_key_values);
if location >= 1 then
deleterec (schemainfo, primary_key_values);
end if;
end deleterec;
---------------------
-- UPDATE RECORD --
---------------------
procedure updaterec
(schemainfo : schema;
pkattribs : attribute_array;
values : attribute_array)
is
position : Integer := 0;
char : Character;
begin
position := findrecord (schemainfo, pkattribs);
--if the record doesn't exist then insert it
if position < 1 then
pl ("That record doesn't exist in the database.", True,
True);
pl ("Insert it instead (menu item 1).", True, True);
pl ("Press Enter to continue...", True, True);
Ada.Text_IO.Get_Immediate (char);
elsif position >= 1 then
deleterec (schemainfo, pkattribs);
insertrec (schemainfo, values);
end if;
end updaterec;
begin
null;
end schema_types;
with util, Ada.Calendar, ada.streams.stream_io;
use util, Ada.Calendar, ada.streams.stream_io;
package attribute_types is
-----------------------------------
-- Forwarding Declarations --
-----------------------------------
type attribute is abstract tagged;
type booleanattribute is tagged;
type integerattribute is tagged;
type stringattribute is tagged;
type dateattribute is tagged;
--------------------------------------
-- Attribute Type Declarations --
--------------------------------------
type attribute is abstract tagged record
name : String (1 .. max_attributename_length) :=
(1 .. max_attributename_length => ' ');
domain : String (1 .. max_typename_length) := (1 ..
max_typename_length => ' ');
isprimarykey : Boolean :=
False;
byte_start : Integer := 0;
byte_end : Integer := 0;
end record;
--------------------------------------
-- Basic Pointer Declarations --
--------------------------------------
type attribute_ptr is access attribute'class;
type attribute_array is array (Integer range <>) of access
attribute'class;
type attribute_array_ptr is access all attribute_array;
procedure to_disc (fout: file_type; item: in out attribute) is
abstract;
function from_disc(fout: file_type; item: attribute) return
attribute'class is abstract;
-----------------------------------
-- Extended Attribute Types --
-----------------------------------
type booleanattribute is new attribute with record
value : Boolean := False;
end record;
type booleanattribute_ptr is access all booleanattribute'class;
procedure to_disc (fout: file_type; item: in out
booleanattribute);
function from_disc(fin: file_type; item: booleanattribute) return
attribute'class;
type integerattribute is new attribute with record
value : Integer := 0;
end record;
type integerattribute_ptr is access all integerattribute'class;
procedure to_disc (fout: file_type; item: in out
integerattribute);
function from_disc(fin: file_type; item: integerattribute) return
attribute'class;
type stringattribute is new attribute with record
value : String (1 .. max_stringlength) := (1 ..
max_stringlength => ' ');
end record;
type stringattribute_ptr is access all stringattribute'class;
procedure to_disc (fout: file_type; item: in out stringattribute);
function from_disc(fin: file_type; item: stringattribute) return
attribute'class;
type dateattribute is new attribute with record
year : Year_Number := 1901;
month : Month_Number := 1;
day : Day_Number := 1;
value : Time := Time_Of (1901, 1, 1);
end record;
type dateattribute_ptr is access all dateattribute'class;
procedure to_disc (fout: file_type; item: in out dateattribute);
function from_disc(fin: file_type; item: dateattribute) return
attribute'class;
end attribute_types;
with ada.text_io, util, ada.calendar;
use util, ada.calendar;
package body attribute_types is
procedure to_disc (fout: file_type; item: in out booleanattribute)
is
begin
item.byte_start := Integer'val (Index (fout));
item.byte_end := Integer'val (Index (fout)) +
(booleanattribute'size / 8) - 7;
booleanattribute'class'output(Stream(fout), item);
end to_disc;
function from_disc(fin: file_type; item: booleanattribute) return
attribute'class is
temp : access attribute'class;
begin
temp := new booleanattribute;
temp.all := booleanattribute'class'input (Stream (fin));
return temp.all;
end from_disc;
procedure to_disc (fout: file_type; item: in out integerattribute)
is
begin
item.byte_start := Integer'val (Index (fout));
item.byte_end := Integer'val (Index (fout)) +
(integerattribute'size / 8) - 7;
integerattribute'class'output(Stream(fout), item);
end to_disc;
function from_disc(fin: file_type; item: integerattribute) return
attribute'class is
temp : access attribute'class;
begin
temp := new integerattribute;
temp.all := integerattribute'class'input (Stream (fin));
return temp.all;
end from_disc;
procedure to_disc (fout: file_type; item: in out stringattribute)
is
begin
item.byte_start := Integer'val (Index (fout));
item.byte_end := Integer'val (Index (fout)) +
(stringattribute'size / 8) - 7;
stringattribute'class'output(Stream(fout), item);
end to_disc;
function from_disc(fin: file_type; item: stringattribute) return
attribute'class is
temp: access attribute'class;
begin
temp := new stringattribute;
temp.all := stringattribute'class'input (Stream (fin));
return temp.all;
end from_disc;
procedure to_disc (fout: file_type; item: in out dateattribute) is
begin
item.byte_start := Integer'val (Index (fout));
item.byte_end := Integer'val (Index (fout)) +
(dateattribute'size / 8) - 11;
dateattribute'class'output(Stream(fout), item);
end to_disc;
function from_disc(fin: file_type; item: dateattribute) return
attribute'class is
temp: access attribute'class;
begin
temp := new dateattribute;
temp.all := dateattribute'class'input (Stream (fin));
return temp.all;
end from_disc;
begin
null;
end attribute_types;
with Ada.Streams.Stream_IO, util, attribute_types,Ada.Calendar; use
util, attribute_types,Ada.Calendar;
package index_types is
---------------------------------
-- Variable Declarations --
---------------------------------
fin : Ada.Streams.Stream_IO.File_Type;
fout : Ada.Streams.Stream_IO.File_Type;
--------------------------------------------------------
-- THIS FILE IS NOT COMPLETE NOR USED YET!!!
-- IT IS INCLUDED BECAUSE IT IS WITH'D
--------------------------------------------------------
--an index is a file
--it contains the primary key value and file position for the
primary key for a primary index
--the spec sounds like only one attribute will make up a primary
key.
--for a secondary index it contains an attribute and a position.
--The spec says only one attribute.
--primary indexes are named after the table it belongs to
<tablename>_PIDX
--secondary indexes are named after the table it belongs to like
<tablename>_SIDX
--each schema object has a list of index names for a table
--initially the list of index names is empty
--the user adds an index to the table and then the index name goes
into the list of indexes on
--the schema
--the schema information will have to be re-written to the table
file when an index is added.
--This is the same for the secondary indexes
--if a tuple that an index is based on is inserted, deleted or
updated then the index must be
--loaded and re-created.
----on updates we only have to change the index if the index value
is being changed.
--The attributes store the name of an index on itself. When we load
the schema
--we go through each attribute and determine if it is indexed then
load that
--index if it is. This gives us the "type" on the index value,
elleviates the
--need to maintain a list of index names in the schema object,
----what do we load an index into?
--There are two types of indexes: primary and secondary
--** note ** the primary index is just like the secondary; it only
has one entry per item
--because there is only
--one item allowed per entry due to the fact that primary keys are
unique.
--The differences in indexes are:
----if we remove a value from a secondary we must match the rrn to
remove the correct
--item; with a primary key there is only one to remove.
----when finding a record, with a primary index when we find the
value we don't
----have to search a bunch of records for the exact tuple match.
With secondary
----, because there are multiple values that are the same with
different rrn's
----we have to search each rrn and compare values to match the
tuple.
--we don't sort as we read the table, we read the table and then
sort the index file.
type index is abstract tagged record
filename : String (1 .. max_index_namelength);
rrn : Ada.Streams.Stream_IO.Count := 0;
end record;
type index_ptr is access all index;
type index_array is array (Integer range <>) of index_ptr;
type booleanindex is tagged record
key : boolean;
end record;
type integerindex is tagged record
key : integer;
end record;
type stringindex is tagged record
key : string(1..max_stringlength);
end record;
type dateindex is tagged record
key : time;
end record;
end index_types;
*************************
* Contents of the table.txt file
* This file is used by the main procedure dbprog.
* It must be labeled tables.txt and placed in the
* same directory as the executable dbprog.exe
*************************
T3(
ID(PRIMARY KEY):INTEGER
);
T2(
DATA(PRIMARY KEY):STRING(15)
);
T4(
II(PRIMARY KEY):DATE
);
T1(
mine(PRIMARY KEY):BOOLEAN
);
*************************
^ permalink raw reply [relevance 3%]
* Re: Char type verification
2006-11-15 21:57 6% ` Georg Bauhaus
@ 2006-11-15 23:15 0% ` KE
0 siblings, 0 replies; 35+ results
From: KE @ 2006-11-15 23:15 UTC (permalink / raw)
Dear George
Many thanks for your detailed answer. I'll most certainly make use of
your advice. However, if you look again, my question was not
- How can I verify whether a character is upper case
Nor was it
- Where, in the library hierarchies of Ada, can I find the character
handling routines
It was intended as "How do you translate this example to Ada? How would
you, as a presumably experienced Ada coder, do it? What hoops would we
jump through?
In other words, I wanted to see some Ada idioms in action to create a
transparent coding of this.
If you believe this simple exercise is not a productive use of your
time, though, I can understand.
Thanks again.
-- KE
Georg Bauhaus wrote:
[snip...]
>
> Or use Ada.Characters.Handling.Is_Upper(c), if you want
> to include characters outside 7bit ASCII.
>
> The C type char, which IIRC might start at -127 or
> at 0, has an implementation defined representation,
> and is a bit vague. The Ada standard frowns upon vague
> things, hence Ada's character type does not have
> theses issues. OTOH, for interfacing with C,
> look at the standard package Interfaces.C.
>
> For more general uses, there are standard packages
> Ada.Strings.Maps, Ada.Strings.Maps.Constants,
> Ada.Characters.Handling, and Ada.Characters.Latin_1.
> There are all kinds of character predicates and
> translation subprograms.
>
> There are variants for Wide_Character, covering
> the BMP of ISO 10646.
>
> Ada 2005, in addition supports Unicode and related
> subprograms.
^ permalink raw reply [relevance 0%]
* Re: Char type verification
@ 2006-11-15 21:57 6% ` Georg Bauhaus
2006-11-15 23:15 0% ` KE
0 siblings, 1 reply; 35+ results
From: Georg Bauhaus @ 2006-11-15 21:57 UTC (permalink / raw)
On Wed, 2006-11-15 at 14:00 -0800, KE wrote:
> Hi
>
> Assume that I have the following C code:
>
> #include <stdio.h>
>
> #define uchar unsigned char
>
>
> static uchar UCASE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
This is the character range 'A' .. 'Z'.
You can simply write
c in 'A' .. 'Z'
in any Boolean context where c is of type Character.
Or use Ada.Characters.Handling.Is_Upper(c), if you want
to include characters outside 7bit ASCII.
The C type char, which IIRC might start at -127 or
at 0, has an implementation defined representation,
and is a bit vague. The Ada standard frowns upon vague
things, hence Ada's character type does not have
theses issues. OTOH, for interfacing with C,
look at the standard package Interfaces.C.
For more general uses, there are standard packages
Ada.Strings.Maps, Ada.Strings.Maps.Constants,
Ada.Characters.Handling, and Ada.Characters.Latin_1.
There are all kinds of character predicates and
translation subprograms.
There are variants for Wide_Character, covering
the BMP of ISO 10646.
Ada 2005, in addition supports Unicode and related
subprograms.
^ permalink raw reply [relevance 6%]
* Re: gnat: can't find package
2006-10-21 17:03 0% ` Tim Rowe
@ 2006-10-21 17:54 0% ` Tim Rowe
0 siblings, 0 replies; 35+ results
From: Tim Rowe @ 2006-10-21 17:54 UTC (permalink / raw)
Tim Rowe wrote:
> Jeffrey R. Carter wrote:
>> Tim Rowe wrote:
>>> The gnat documentation tells me to expect a package
>>> Ada.Strings.Maps.Constants, in which I should find
>>> Lower_Set : constant Character_Set;
>>>
>>> It doesn't seem to be there. AdaGIDE doesn't offer "Constants" as a
>>> completion for "Ada.Strings.Maps.", the compiler doesn't recognise
>>> Lower_Set, and grep doesn't turn up Lower_Set anywhere in the gnat
>>> libs directory. Is it anywhere to be found, and if so how do I get
>>> the compiler to recognise it? And if it isn't, how do I convert a
>>> string to lower case?
>>
>> This is a standard package. See ARM A.4.6. If you're unable to with
>> it, there's a problem with your installation.
>
> That's what I thought. The installation is the one that
> gnat-3.15p-nt.exe gave me, so if it's not in there then I don't know
> where I can get it. The other libraries I've tried are in there.
Ok, cancel that. Found it (although AdaGIDE seems to be uncertain about it).
^ permalink raw reply [relevance 0%]
* Re: gnat: can't find package
2006-10-21 6:17 0% ` Jeffrey R. Carter
@ 2006-10-21 17:03 0% ` Tim Rowe
2006-10-21 17:54 0% ` Tim Rowe
0 siblings, 1 reply; 35+ results
From: Tim Rowe @ 2006-10-21 17:03 UTC (permalink / raw)
Jeffrey R. Carter wrote:
> Tim Rowe wrote:
>> The gnat documentation tells me to expect a package
>> Ada.Strings.Maps.Constants, in which I should find
>> Lower_Set : constant Character_Set;
>>
>> It doesn't seem to be there. AdaGIDE doesn't offer "Constants" as a
>> completion for "Ada.Strings.Maps.", the compiler doesn't recognise
>> Lower_Set, and grep doesn't turn up Lower_Set anywhere in the gnat
>> libs directory. Is it anywhere to be found, and if so how do I get the
>> compiler to recognise it? And if it isn't, how do I convert a string
>> to lower case?
>
> This is a standard package. See ARM A.4.6. If you're unable to with it,
> there's a problem with your installation.
That's what I thought. The installation is the one that
gnat-3.15p-nt.exe gave me, so if it's not in there then I don't know
where I can get it. The other libraries I've tried are in there.
^ permalink raw reply [relevance 0%]
* Re: gnat: can't find package
2006-10-21 1:02 6% gnat: can't find package Tim Rowe
2006-10-21 2:57 0% ` Anh Vo
@ 2006-10-21 6:17 0% ` Jeffrey R. Carter
2006-10-21 17:03 0% ` Tim Rowe
1 sibling, 1 reply; 35+ results
From: Jeffrey R. Carter @ 2006-10-21 6:17 UTC (permalink / raw)
Tim Rowe wrote:
> The gnat documentation tells me to expect a package
> Ada.Strings.Maps.Constants, in which I should find
> Lower_Set : constant Character_Set;
>
> It doesn't seem to be there. AdaGIDE doesn't offer "Constants" as a
> completion for "Ada.Strings.Maps.", the compiler doesn't recognise
> Lower_Set, and grep doesn't turn up Lower_Set anywhere in the gnat libs
> directory. Is it anywhere to be found, and if so how do I get the
> compiler to recognise it? And if it isn't, how do I convert a string to
> lower case?
This is a standard package. See ARM A.4.6. If you're unable to with it,
there's a problem with your installation.
--
Jeff Carter
"I was hobbling along, minding my own business, all of a
sudden, up he comes, cures me! One minute I'm a leper with
a trade, next minute my livelihood's gone! Not so much as a
'by your leave!' You're cured, mate. Bloody do-gooder!"
Monty Python's Life of Brian
76
^ permalink raw reply [relevance 0%]
* Re: gnat: can't find package
2006-10-21 1:02 6% gnat: can't find package Tim Rowe
@ 2006-10-21 2:57 0% ` Anh Vo
2006-10-21 6:17 0% ` Jeffrey R. Carter
1 sibling, 0 replies; 35+ results
From: Anh Vo @ 2006-10-21 2:57 UTC (permalink / raw)
Tim Rowe wrote:
> The gnat documentation tells me to expect a package
> Ada.Strings.Maps.Constants, in which I should find
> Lower_Set : constant Character_Set;
>
It is in there. You need to make it visible with dot notation or use
clause. Check the scope and visibility rules from the Ada Language
Reference Manual (LRM).
AV
^ permalink raw reply [relevance 0%]
* gnat: can't find package
@ 2006-10-21 1:02 6% Tim Rowe
2006-10-21 2:57 0% ` Anh Vo
2006-10-21 6:17 0% ` Jeffrey R. Carter
0 siblings, 2 replies; 35+ results
From: Tim Rowe @ 2006-10-21 1:02 UTC (permalink / raw)
The gnat documentation tells me to expect a package
Ada.Strings.Maps.Constants, in which I should find
Lower_Set : constant Character_Set;
It doesn't seem to be there. AdaGIDE doesn't offer "Constants" as a
completion for "Ada.Strings.Maps.", the compiler doesn't recognise
Lower_Set, and grep doesn't turn up Lower_Set anywhere in the gnat libs
directory. Is it anywhere to be found, and if so how do I get the
compiler to recognise it? And if it isn't, how do I convert a string to
lower case?
TIA,
Tim Rowe
^ permalink raw reply [relevance 6%]
* Re: String filtering
@ 2005-09-27 14:08 7% ` Georg Bauhaus
0 siblings, 0 replies; 35+ results
From: Georg Bauhaus @ 2005-09-27 14:08 UTC (permalink / raw)
David Trudgett wrote:
> Yes, well, functions work that way in Ada (fortunately, or
> unfortunately, I don't know). I could have made it a procedure with an
> "in out" parameter, but I like functional programming better.
> Unfortunately, I haven't been able to do proper functional style
> programming in Ada so far, having been thwarted by strong typing and
> lack of "out" parameters in functions.
Here's a filter then.
with Ada.Containers.Vectors;
package Character_Vectors is
new Ada.Containers.Vectors(Element_Type => Character,
Index_Type => Positive);
with Character_Vectors;
with Ada.Strings.Maps.Constants;
procedure filter is
use Character_Vectors;
input: Vector;
output: Vector;
procedure save_good_ones(c: Cursor) is
use Ada.Strings.Maps;
Alpha_Num_Space_Set : constant Character_Set
:= Constants.Alphanumeric_Set or To_Set(' ');
begin
if Is_In(Element(c), Alpha_Num_Space_Set) then
append(output, Element(c));
end if;
end save_good_ones;
begin
Iterate(input, save_good_ones'access);
end filter;
^ permalink raw reply [relevance 7%]
* Re: Data table text I/O package?
2005-07-02 10:24 0% ` Dmitry A. Kazakov
@ 2005-07-06 22:04 0% ` Randy Brukardt
0 siblings, 0 replies; 35+ results
From: Randy Brukardt @ 2005-07-06 22:04 UTC (permalink / raw)
"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:1vlfc01w9jkzj$.k4rp7yhtuoj3$.dlg@40tude.net...
...
> > if Ada.Strings.Unbounded.Index (Ada.Strings.Unbounded.Translate
> > (Current.Line, Ada.Strings.Maps.Constants.Lower_Case_Map),
> > Ada.Strings.Unbounded.To_String (Pattern.Line)) /= 0 then
>
> I'm using a table of tokens instead. The string is matched against the
> table for a longest token that matches. And I always use anchored search.
I
> tend to do everything in one pass and Ada fits here well.
That's actually what the above is doing: a single match in a list of
patterns. It usually is inside of a loop.
Some of the matching uses a special Match_Start routine which is cheaper
than Index; but of course that only works because I know how an unbounded
string works, and Ada lets be create a child to use that information.
I'm not certain what you mean by an "anchored search", but I don't expect
that too work too well on e-mail (which is just a mass of text). I do think
it wouldn't have been any harder to have used type String items here instead
of Unbounded_String. The only reason I used Unbounded_String was to see how
easy or hard it really was to use that package - I won't make that mistake
again.
Randy.
^ permalink raw reply [relevance 0%]
* Re: Data table text I/O package?
2005-07-02 1:54 5% ` Randy Brukardt
@ 2005-07-02 10:24 0% ` Dmitry A. Kazakov
2005-07-06 22:04 0% ` Randy Brukardt
0 siblings, 1 reply; 35+ results
From: Dmitry A. Kazakov @ 2005-07-02 10:24 UTC (permalink / raw)
On Fri, 1 Jul 2005 20:54:18 -0500, Randy Brukardt wrote:
> And if you don't know what you are analyzing for, Ada is hardly the
> programming language to be using. (Unless you're a hard-core Ada nut [a
> category that I qualify in]; but then you hardly need advice from this
> group.) You need a much more dynamic language, perhaps even those Unix
> filters.
I think it depends. I have a quite opposite experience. I'm lazy and always
start to write a UNIX script. After a couple of hours fighting with that
mess I note (usually to late) that to write it in Ada (or even in ANSI C)
would take twice as short.
> For instance, there isn't a way to search for an unbounded string in another
> unbounded string. [TF puts pretty much everything into lists of unbounded
> strings, because it's impossible to predict what sort of string lengths
> items will have.] You have to use To_String to convert to a regular string,
> which is ugly (especially without use clauses):
Yes.
All built-in string types should have a common ancestor.
Ada.Strings.Unbounded was and remains an ugly hack.
> if Ada.Strings.Unbounded.Index (Ada.Strings.Unbounded.Translate
> (Current.Line, Ada.Strings.Maps.Constants.Lower_Case_Map),
> Ada.Strings.Unbounded.To_String (Pattern.Line)) /= 0 then
I'm using a table of tokens instead. The string is matched against the
table for a longest token that matches. And I always use anchored search. I
tend to do everything in one pass and Ada fits here well.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [relevance 0%]
* Re: Data table text I/O package?
@ 2005-07-02 1:54 5% ` Randy Brukardt
2005-07-02 10:24 0% ` Dmitry A. Kazakov
0 siblings, 1 reply; 35+ results
From: Randy Brukardt @ 2005-07-02 1:54 UTC (permalink / raw)
"Alexander E. Kopilovich" <aek@VB1162.spb.edu> wrote in message
news:mailman.122.1120188122.17633.comp.lang.ada@ada-france.org...
> Randy Brukardt wrote:
...
> You obviosly don't like data very much, but for a scientist that
scientific
> data (often including raw experimental data) is one of the most valuable
> things. It certainly deserves attentive look (at least, from time to
time),
> not just a bureacratic "analysis".
I'm not speaking about data in general (that would be silly), but about it
in the context of Ada programming. (Or have you forgotten the purpose of
this newsgroup?)
It makes perfect sense to look at raw data if you don't know what to analyze
for and you need to find some patterns to give some insight. I suppose there
also is an amount of idle curiousity, too (certainly that happens to me in
these sorts of circumstances -- that's why I might look at web logs or the
results of a game analysis). But I hardly think it makes sense to design
software based on idle curiousity.
And if you don't know what you are analyzing for, Ada is hardly the
programming language to be using. (Unless you're a hard-core Ada nut [a
category that I qualify in]; but then you hardly need advice from this
group.) You need a much more dynamic language, perhaps even those Unix
filters. Its quite possible that Jacob shouldn't be using Ada at all for his
tasks, and thus he's trying to fit a square peg into a round hole.
> > Truthfully, if what you described above is true, you probably ought to
be
> > programming in Perl (ugh) or Python. Because Ada's text processing is
its
> > weak link, and it makes little sense to write any significant amount of
text
> > processing code in Ada.
>
> It would be interesting to hear reply from Robert Dewar to this opinion
about
> text processing capabilities of Ada -:) . Actually, serious text
processing
> is perfectly possible with Ada, and in fact Ada is more suitable for it
than
> Perl. Ada is unsuitable for quick scripting (especially by novice), but it
> is true for all application domains, it is true for numerical computations
> as well as for text processing .
Certainly, serious text processing is *possible* in Ada. (My Trash Finder
spam filter certainly is an extensive text processing application!!) And of
course, the benefits of Ada do apply (particular type checking and good
runtime checks). But, Ada text processing code is just painful to write, and
it's quite hard to read. That's true no matter whether you use plain strings
or unbounded strings.
One of my original intents with TF was to show a good example of Ada code to
non-Ada programmers. But the code got so long-winded that I gave up on that
idea fairly early on. Moreover, the standard routines in
Ada.Strings.Unbounded were just not fast enough in some cases, and I had to
write special routines that understand the internal representation of an
unbounded string. Yuck. (Ada 200Y will help this a bit, at least the
searching has been improved.)
For instance, there isn't a way to search for an unbounded string in another
unbounded string. [TF puts pretty much everything into lists of unbounded
strings, because it's impossible to predict what sort of string lengths
items will have.] You have to use To_String to convert to a regular string,
which is ugly (especially without use clauses):
if Ada.Strings.Unbounded.Index (Ada.Strings.Unbounded.Translate
(Current.Line, Ada.Strings.Maps.Constants.Lower_Case_Map),
Ada.Strings.Unbounded.To_String (Pattern.Line)) /= 0 then
Even with a use clause for Ada.Strings.Unbounded (in which case you can't
have one for Ada.Strings.Fixed, else things get very ambiguous):
if Index (Translate (Current.Line,
Ada.Strings.Maps.Constants.Lower_Case_Map), To_String (Pattern.Line) /= 0
then
So, it's possible to write this sort of code in Ada, and get decent
performance, too, but the result isn't particularly readable,
understandable, or maintainable. It's a lot easier to write this in Perl,
although the result would probably be a bit harder to maintain. Not having
used Python, I can't say for sure, but I'd certainly hope that it would be
easier that this to write (and read!) something simple like a
case-insensitive search for a pattern.
If I had used regular strings, the complexity would have been about the
same, just in different places. (In hindsight, I probably wouldn't have used
unbounded strings at all, they just didn't buy enough simplification.)
So, I stand by my statements. There is more than 8,000 lines of text
processing code in TF, all of which looks like this. And all I can say is
that I certainly hope that there is a better way somewhere, even though such
a way isn't really possible for Ada.
Randy.
^ permalink raw reply [relevance 5%]
* Re: Ada bench : count words
@ 2005-04-01 20:58 5% ` Georg Bauhaus
0 siblings, 0 replies; 35+ results
From: Georg Bauhaus @ 2005-04-01 20:58 UTC (permalink / raw)
jtg wrote:
>> I think we have tolerated that C guys telling us that Ada is slow for too
>> long time. Game is over! (:-))
>>
> I'm afraid I don't understand. Who is the winner?
> Maybe you meant: The game just begins :-)
Here's another program for the shootout, regular expression
matching. This is the Spitbol patterns version. Maybe the
report printed by the program needs the removal of leeding
spaces in Natural'image?
with
GNAT.Spitbol.Patterns,
Ada.Command_Line,
Ada.Strings.Maps.Constants,
Ada.Text_IO;
procedure regexmatch is
use GNAT.Spitbol.Patterns, Ada.Text_IO, Ada.Strings.Maps;
package Spit renames GNAT.Spitbol;
dollar_1, dollar_2, dollar_3: Spit.VString;
Digit: constant Character_Set := Constants.Decimal_Digit_Set;
D: constant Pattern := Any(Digit);
Area_Code: constant Pattern := (D & Fence & D & D) ** dollar_1;
Exchange: constant Pattern := (D & D & D) ** dollar_2;
Last_Four: constant Pattern := (D & D & D & D) ** dollar_3;
-- Fence: consider "(123 " after two BreakX calls in `re` below
re: constant Pattern :=
BreakX(Digit or To_Set('(')) -- scan upto digit or left paren
& ( '(' & Area_Code & ')' -- parenthesized area code
or -- or
Area_Code) -- just area code
& ' ' -- one space
& Exchange & Any(" -") & Last_Four
& ( RPos(0) or NotAny(Digit) ); -- at EOL or a non-digit
type String_Pointer is access String;
phones: array(1 .. 50) of String_Pointer;
line_count: Natural;
match_count: Natural := 0;
NUM: Natural;
procedure set_NUM is
use Ada.Command_Line;
begin
NUM := Positive'value(Argument(1));
exception
when Constraint_Error => NUM := 1;
end set_NUM;
procedure read_lines is
last: Natural;
buf: String(1 .. 80);
begin
line_count := phones'first;
loop
Get_Line(buf, last);
phones(line_count) := new String'(buf(buf'first .. last));
line_count := line_count + 1;
end loop;
exception
when End_Error =>
line_count := line_count - 1;
end read_lines;
begin
set_NUM;
read_lines;
Anchored_Mode := True;
while NUM > 0 loop
NUM := NUM - 1;
matching:
for p in phones'first .. line_count loop
if Match(phones(p).all, re) then
if NUM = 0 then
match_count := match_count + 1;
put_line(Natural'image(match_count)
& ": "
& "(" & Spit.S(dollar_1) & ") "
& Spit.S(dollar_2) & "-" & Spit.S(dollar_3));
end if;
end if;
end loop matching;
end loop;
end regexmatch;
^ permalink raw reply [relevance 5%]
* Re: variable lenght strings
2004-10-21 17:52 7% variable lenght strings fabio de francesco
@ 2004-10-21 23:05 0% ` Stephen Leake
0 siblings, 0 replies; 35+ results
From: Stephen Leake @ 2004-10-21 23:05 UTC (permalink / raw)
To: comp.lang.ada
fmdf@tiscali.it (fabio de francesco) writes:
> 1) Is it possible to use Get_Line with Unbounded and/or Bounded
> Strings?
If you are using GNAT, you can use Ada.Strings.Unbounded.Text_IO.
> 2) If not, how should user input be managed when lines length isn't
> known a priori?
Ada.Text_IO.Get_Line takes a String argument; if it isn't
filled, you can call Ada.Strings.Unbounded on it.
The tricky part is what to do if your initial guess at a max length is
too short. You can write a loop; keep appending chunks of input until
Get_Line returns Last < Item'last.
> <snip stuff about Find_Token>
>
> Ok, please let me know if the following is the correct usage:
"Correct usage" is whatever works for your application!
>
>
> with Ada.Text_IO, Ada.Strings, Ada.Strings.Fixed,
> Ada.Strings.Maps, Ada.Strings.Maps.Constants;
> use Ada.Text_IO, Ada.Strings, Ada.Strings.Fixed,
> Ada.Strings.Maps, Ada.Strings.Maps.Constants;
>
> procedure Tokenize is
>
> S : constant String := ".symbol HP = High_Pressure "; -- Line A
> F : Positive := S'First;
> L : Natural := S'Last;
> W : String( 1..30 );
>
> begin
> loop
> Find_Token(S(F..L), Alphanumeric_Set or To_Set("_."), Inside, F,
> L);
It would be best to declare a variable to hold Alphanumeric_Set or
To_Set("_.").
> if L /= 0 then
This could be 'exit when L = 0', but it's really a style issue.
> Put_Line( Positive'Image( F ) & ( L - F ) * ' ' &
> Natural'Image( L ) );
> Move( S( F..L ), W );
Named association is better here; I always forget which is the target
and which the source.
> Put_Line( ' ' & W );
> F := L + 1;
> L := S'Last;
> else
> exit;
> end if;
> end loop;
> end Tokenize;
>
>
> Is it correct to check the "L" value as a condition to exit the
> loop?
Yes.
--
-- Stephe
^ permalink raw reply [relevance 0%]
* variable lenght strings
@ 2004-10-21 17:52 7% fabio de francesco
2004-10-21 23:05 0% ` Stephen Leake
0 siblings, 1 reply; 35+ results
From: fabio de francesco @ 2004-10-21 17:52 UTC (permalink / raw)
Hi,
while studying from "Ada as a 2nd Language" I am having some problem
to cope with Strings (Fixed, Unbounded and Bounded) manipulation and
especially with assigning between different types of them and with
overall with input/output.
1) Is it possible to use Get_Line with Unbounded and/or Bounded
Strings?
2) If not, how should user input be managed when lines length isn't
known a priori?
3) I have to write a program that parses a file in which there are
lines that have to be "tokenized". I didn't find any Find_Token()
usage example on the Book so I wrote a little piece of code in order
to understand the procedure workings on a fixed string (Line A) that
simulates file input.
Think that I am used with C function strtok() and I must say that Ada
Find_Token is much more elegant and not destructive as strtok() is.
Ok, please let me know if the following is the correct usage:
with Ada.Text_IO, Ada.Strings, Ada.Strings.Fixed,
Ada.Strings.Maps, Ada.Strings.Maps.Constants;
use Ada.Text_IO, Ada.Strings, Ada.Strings.Fixed,
Ada.Strings.Maps, Ada.Strings.Maps.Constants;
procedure Tokenize is
S : constant String := ".symbol HP = High_Pressure "; -- Line A
F : Positive := S'First;
L : Natural := S'Last;
W : String( 1..30 );
begin
loop
Find_Token(S(F..L), Alphanumeric_Set or To_Set("_."), Inside, F,
L);
if L /= 0 then
Put_Line( Positive'Image( F ) & ( L - F ) * ' ' &
Natural'Image( L ) );
Move( S( F..L ), W );
Put_Line( ' ' & W );
F := L + 1;
L := S'Last;
else
exit;
end if;
end loop;
end Tokenize;
Is it correct to check the "L" value as a condition to exit the loop?
Thank you in advance for any help,
Fabio De Francesco
^ permalink raw reply [relevance 7%]
* Re: questions from a newbie
2004-07-15 13:45 6% ` Steve
@ 2004-07-15 14:44 5% ` Georg Bauhaus
1 sibling, 0 replies; 35+ results
From: Georg Bauhaus @ 2004-07-15 14:44 UTC (permalink / raw)
zork <zork@nospam.com> wrote:
:
: if c in 'A'..'Z' or c in 'a'..'z' or c in '0'..'9' then
:
:
: if c in ('A'..'Z', 'a'..'z', '0'..'9') then
This is the purpose of Ada.Strings.Maps etc.
In Ada.Strings.Maps.Constants you will find predefined
Character_Set constant that match yours.
: Also, I know you can do the following:
:
: type new_type is array(1..20) of string(1..50);
: words : new_type;
: index : integer := 20;
: words (15) (index ..index) := "K";
:
: however I find that I cannot instead say:
:
: words(15)(index):="K";
:
: why is this so?
...(index) denotes a Character, one component of an array,
...(index .. index) denotes an array slice.
The index values can in general be results of computations at
runtime, i.e., ...(n .. m). What kind of thing other than
an array slice should (n .. m) denote? OTOH, ...(n) where n
is an index value cannot but denote one array component.
: I get a "Type mismatch in assignment statement, continuing"
: error. It does however work when I use words(15)(index):='K'. The rational
: behind this is that (index..index) represents a range - hence a string -
: whereas (index) represents a single character?
^ permalink raw reply [relevance 5%]
* Re: questions from a newbie
@ 2004-07-15 13:45 6% ` Steve
2004-07-15 14:44 5% ` Georg Bauhaus
1 sibling, 0 replies; 35+ results
From: Steve @ 2004-07-15 13:45 UTC (permalink / raw)
"zork" <zork@nospam.com> wrote in message news:40f684a8@dnews.tpgi.com.au...
> Hi, I just started a course in ada. I just have 2 questions at present.
>
> -------------
> q1) can:
>
> c : character;
>
> if c in 'A'..'Z' or c in 'a'..'z' or c in '0'..'9' then
> ....
> end if;
>
> be written as something like:
>
> c : character;
>
> if c in ('A'..'Z', 'a'..'z', '0'..'9') then
> ....
> end if;
> -------------
Not directly, but you can make use the of standard Ada libraries:
Ada.Strings.Maps
Ada.Strings.Maps.Constants
and do something like:
if Is_In( c, Alphanumeric_Set ) then
...
end if;
Since you're a newbie, I recommend you peruse annex A of the Ada 95
reference manual; it describes the predefined language enviroment, which is
basically a list of all of the standard libraries.
You can download a copy from:
http://www.adaic.org/standards/ada95.html
>
> Also, I know you can do the following:
>
> type new_type is array(1..20) of string(1..50);
> words : new_type;
> index : integer := 20;
> words (15) (index ..index) := "K";
>
> however I find that I cannot instead say:
>
> words(15)(index):="K";
>
> why is this so? I get a "Type mismatch in assignment statement,
continuing"
> error. It does however work when I use words(15)(index):='K'. The rational
> behind this is that (index..index) represents a range - hence a string -
> whereas (index) represents a single character?
>
You answered your own question here.
If you're coming from a different programming language, you may find that
Ada is kind of a "hard ass" about the syntax it will accept. When you get
over the frustration and find that more programs work correctly after you
get past the compiler, you may never want to go back.
Steve
(The Duck)
> Any insight most helpful.
>
> Cheers,
> zork
>
>
^ permalink raw reply [relevance 6%]
* Re: conversion
@ 2003-06-27 18:42 7% ` tmoran
0 siblings, 0 replies; 35+ results
From: tmoran @ 2003-06-27 18:42 UTC (permalink / raw)
>Hmmm. Where to begin. You are thinking in C about Ada concepts. That
>is confusing you because the Ada mappings are different. In Ada, the
As a general rule, if something seems inordinately hard to do in Ada,
you are probably not using Ada appropriately. In the case of strings,
declaring dynamically sized strings, passing strings as dynamically sized
parameters, using concatenation, and, especially, using slices will handle
a great many string processing tasks. eg,
procedure Process_Line(Line : in String) is
-- From "Fred Smith #12345; John Jones, Albert"
-- make 2 calls on Process_First_Name
-- Process_Full_Name("Smith, Fred");
-- Process_Full_Name("Jones, John");
First, Last : Natural;
begin
First := Line'first;
loop
Ada.Strings.Fixed.Find_Token
(Source=>Line(First .. Line'last),
Set =>Ada.Strings.Maps.Constants.Letter_Set,
Test =>Ada.Strings.Inside,
First =>First,
Last =>Last);
exit when Last = 0;
declare
use Ada.Strings;
use Ada.Strings.Maps.Constants;
First_Name : String renames Line(First .. Last);
begin
Fixed.Find_Token(Line(Last+1 .. Line'last), Letter_Set, Inside,
First, Last);
exit when Last = 0;
Process_Full_Name(Line(First .. Last) & ", " & First_Name);
end;
First := Last+1;
end loop;
end Process_Line;
...
Line : String(1 .. 80);
Last : Natural;
...
Ada.Text_IO.Get_Line(Input, Line, Last);
Process_Line(Line(Line'first .. Last));
^ permalink raw reply [relevance 7%]
* Re: config files proposal
2002-06-04 19:55 5% ` Ted Dennison
@ 2002-06-09 20:43 0% ` Stephen Leake
0 siblings, 0 replies; 35+ results
From: Stephen Leake @ 2002-06-09 20:43 UTC (permalink / raw)
dennison@telepath.com (Ted Dennison) writes:
> Darren New <dnew@san.rr.com> wrote in message
> news:<3CFB94A7.A455B8DD@san.rr.com>...
> > I think they should be case sensitive unless there's a standard way of
> > converting uppercase unicode to lowercase unicode in Ada's libraries.
>
> We need to match up well with what's in the Ada standard I think.
>
> The Ada standard has an Ada.Strings.Maps.Constants.Lower_Case_Map and
> an Ada.Strings.Wide_Maps.Wide_Constants.Lower_Case_Map. There is no
> reason why we can't define things to say that keys will be fed through
> the appropriate Lower_Case_Map before being matched.
Good point.
> If the language itself has some kind of problem with
> Ada.Strings.Wide_Maps.Wide_Constants.Lower_Case_Map, I say that is
> the language's problem, and outside the scope of a configuration
> item facility to try to worry about fixing. As long as we define
> what we are doing carfully this way, it is still explicit. If we
> stick to using the standard library, things should at least behave
> for people the way they have come to expect them to behave when
> using Ada.
According to my interpretation of recent posts by Robert Dewar (is
that qualified enough :), there is very little use of Wide_String. So
it's not clear whether Lower_Case_Map is "what people expect". But I
agree it would be a good place to start.
Perhaps case sensitivity should be an option in the config file API.
--
-- Stephe
^ permalink raw reply [relevance 0%]
* Re: config files proposal
@ 2002-06-04 19:55 5% ` Ted Dennison
2002-06-09 20:43 0% ` Stephen Leake
0 siblings, 1 reply; 35+ results
From: Ted Dennison @ 2002-06-04 19:55 UTC (permalink / raw)
Darren New <dnew@san.rr.com> wrote in message news:<3CFB94A7.A455B8DD@san.rr.com>...
> I think they should be case sensitive unless there's a standard way of
> converting uppercase unicode to lowercase unicode in Ada's libraries.
We need to match up well with what's in the Ada standard I think.
The Ada standard has an Ada.Strings.Maps.Constants.Lower_Case_Map and
an Ada.Strings.Wide_Maps.Wide_Constants.Lower_Case_Map. There is no
reason why we can't define things to say that keys will be fed through
the appropriate Lower_Case_Map before being matched.
If the language itself has some kind of problem with
Ada.Strings.Wide_Maps.Wide_Constants.Lower_Case_Map, I say that is the
language's problem, and outside the scope of a configuration item
facility to try to worry about fixing. As long as we define what we
are doing carfully this way, it is still explicit. If we stick to
using the standard library, things should at least behave for people
the way they have come to expect them to behave when using Ada.
--
T.E.D.
Home - mailto:dennison@telepath.com (Yahoo: Ted_Dennison)
Homepage - http://www.telepath.com/dennison/Ted/TED.html
^ permalink raw reply [relevance 5%]
* Re: Newbie question
@ 2002-01-01 21:26 7% ` Michal Nowak
0 siblings, 0 replies; 35+ results
From: Michal Nowak @ 2002-01-01 21:26 UTC (permalink / raw)
To: comp.lang.ada usegroup->mailing list gateway
On 01-12-31 at 17:51 Jasbinder S Uppal wrote:
[snip]
>PS Michal hope ur feeling better, if not, a dose of Ada will certainly fix
>any ailments u have.....
Thank you sincerely, I'm OK now. I'm glad I've been a bit helpful. I hope
that the errors I made did not confused you. I'm newbie also...My advices
were a bit in C-tone, I wasn't well aware of Ada strings. I learned a bit
more when I was lying in bed and reading Cohen's book. Maybe this will be
more helpful than my last "advices".
If you have access to Reference Manual (HTML files are installed with GNAT,
so you should), look at Annex A, section 4 (particularly 4.2).
There is useful package Ada.Strings.Maps and Ada.Strings.Fixed (the latter
in case if you use fixed length Strings). It will be much easir to parse
the input line using functions and procedures from these packages. I think
that procedure Find_Token will be helpful. A token can be a sequence of
characters belonging to some set. The second parameter of Find_Token is of
type Character_Set. As I remember, the first word was the name of place
(so it consists of upper and lowercase letters) and the second was road
number (consisting of letters and numbers) and the rest was hour (only
numbers). In Ada.Strings.Maps.Constants there are predefined sets of
chracters:
Alphanumeric_Set : ISO-8859-1 letters and numbers,
Letter_Set : ISO-8859-1 letters,
Decimal_Digit_Set : Decimal numbers.
Alphanumeric_Set consists not only Enlish letters, but also letters with
diacritical marks. This piece of code shows chracters from this set:
with Ada.Strings.Maps.Constants;
use Ada.Strings.Maps; --for procedures
use Ada.Strings.Maps.Constants; --for constant sets
with Ada.Text_IO;
use Ada.Text_IO;
procedure Show_Set is
begin
Put (To_Sequence(Alphanumeric_Set) );
end Show_Set;
If you apply Find_Token to extracting values, all can be written
like this:
Find_Token (Input_Line, Letter_Set, Inside, From, To);
In From and To variables you will get beginning and end of first
word. You may than use slice operation to get the first word into
string:
Place := To_Unbounded_String (Input_Line (From .. To) );
(I assume here, that place is of type Unbounded_String, declared in
Ada.Strings.Unbounded, you may need to "with" this package);
Than you may repeat the search for the second word:
Find_Token (Input_Line (To + 1 .. Input_Line'Last), Letter_Set, Inside, From, To);
^^
This To was obtained in first call to Find_Token.
And then extract the second word and do the same for numbers.
I hope I was more helpful now and that I was not to late.
Enjoy,
Mike(
-----------------------------------------
____|
\%/ |~~\
O |
o>> Mike Nowak |
T |
/ > vinnie@inetia.pl |
http://www.geocities.com/vinnie14pl _|__
^ permalink raw reply [relevance 7%]
* Re: avl tree - booch components
2001-09-10 21:52 5% ` Jeffrey D. Cherry
@ 2001-09-10 21:53 5% ` Jeffrey D. Cherry
1 sibling, 0 replies; 35+ results
From: Jeffrey D. Cherry @ 2001-09-10 21:53 UTC (permalink / raw)
I once created the following package and driver program for a colleague.
It was derived from a much larger project where we used an AVL tree as
part of a symbol table for a FORTRAN parser. It compiles with GNAT v3.13p
under Windows 2000 and the August 19, 2001 version of the Booch components.
Though comments are somewhat sparse, there is some explanation regarding
instantiating the AVL tree. Hope this helps.
--
Regards,
Jeffrey D. Cherry
Senior IV&V Analyst
Logicon Operations and Services
Logicon Inc.
a Northrop Grumman company
-- This is a simple package to store "keywords" and an associated data
-- item as an abstract data object. We'll refer to this abstract data
-- object simply as the keyword container.
package Keyword_Manager is
-- This is a dummy type so we can associate some kind of data with
-- a key field. The dummy type can, of course, be very complex if
-- it is appropriate for the problem. It could also be a generic
-- parameter. For that matter, the "key" type (strings in this
-- example) could be a generic parameter as well. I won't do that
-- here since too many levels of generic instantiations will detract
-- from what I'm trying to show.
type ID_Type is (Unknown_ID, Known_ID, Another_ID, Yet_Another_ID);
-- Clear the keyword container of all (keyword,ID) pairs so that we
-- have an empty keyword container.
procedure Clear_Keywords;
-- Return true if the keyword container is empty and return false
-- if there are one or more (keyword,ID) pairs in the keyword container.
function Is_Empty return boolean;
-- Return the number of (keyword,ID) pairs in the keyword container.
function Number return natural;
-- Insert a keyword and its associated data into the keyword container.
-- If the keyword already exists, then the ignore the data. (Normally
-- we would want to signal some kind of fault - perhaps via an exception.
-- However, we don't want to focus on error processing in this example.)
procedure Insert(
Keyword : in string;
ID : in ID_Type);
-- Return true if the given keyword exists in the keyword container and
-- return false if it does not exist in the keyword container.
function Exists(Keyword : in string) return boolean;
-- Return the ID associated with the given keyword. If the keyword
-- doesn't exist in the keyword container, then Unknown_ID is returned.
-- (Again, this should probably raise an exception but we're not
-- focusing on error processing.)
function Identify(Keyword : in string) return ID_Type;
-- Write the contents of the keyword container to standard output.
-- Normally we would want to make this ability much more flexible,
-- but we make another concession for a simple example.
procedure Put_Keywords;
end Keyword_Manager;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Strings.Maps.Constants;
with BC.Containers.Trees.AVL.Print;
with BC.Support.Unmanaged_Storage;
package body Keyword_Manager is
-- A node for the keyword table. This is the information stored in
-- the AVL tree. We use unbounded strings since we don't know the
-- length of our key strings. If we did, we could use the bounded
-- form from Ada.Strings.Bounded.
type Keyword_Node is
record
Keyword : Unbounded_String := Null_Unbounded_String;
ID : ID_Type := Unknown_ID;
end record;
-- Eventually, we'll need some kind of storage management for the
-- Keyword_Node structures and the tree that stores the data. For
-- this example, we don't care too much about storage issues, so we'll
-- use the default unmanaged storage provided by the Booch components.
subtype Tree_Storage_Pool is BC.Support.Unmanaged_Storage.Pool;
Tree_Storage : Tree_Storage_Pool;
-- Equality function used to identify equivalent nodes in the AVL tree.
-- Notice that the test is case insensative.
function Same_Keyword(Left, Right : in Keyword_Node) return boolean is
use Ada.Strings.Maps.Constants;
begin -- Same_Keyword
return Translate(Left.Keyword, Lower_Case_Map) =
Translate(Right.Keyword, Lower_Case_Map);
end Same_Keyword;
-- Ordering function used to order nodes in the AVL tree. Notice that
-- the nodes are in reverse alphabetical order and are case insensative.
function Is_Before(Left, Right : in Keyword_Node) return boolean is
use Ada.Strings.Maps.Constants;
begin -- Is_Before
return Translate(Left.Keyword, Lower_Case_Map) >
Translate(Right.Keyword, Lower_Case_Map);
end Is_Before;
-- First create an abstract container that can hold our Keyword_Nodes and
-- can test for two identical Keyword_Nodes.
package Keyword_Containers is
new BC.Containers(Item => Keyword_Node, "=" => Same_Keyword);
-- Since an abstract tree is just another form of an abstract container,
-- we create an abstract container that uses an abstract tree structure.
-- No new information is required to be given to the abstract tree
-- container and so this is just a simple instantiation built off our
-- previous container.
package Keyword_Container_Trees is new Keyword_Containers.Trees;
-- Now we must define a substantial form for the abstract tree container.
-- This is where we decide to use an AVL form of a tree rather than some
-- other form (e.g., binary or multiway). Since a tree stores data in
-- an ordered fashion, we must tell the AVL tree how to order our data.
-- This is done with the ordering function we defined above (function
-- Is_Before). This will also be our concrete package that must deal
-- with both allocation and deallocation of memory resources for the
-- tree nodes.
package Keyword_Trees is
new Keyword_Container_Trees.AVL(
"<" => Is_Before,
Storage_Manager => Tree_Storage_Pool,
Storage => Tree_Storage);
-- Okay, we can now define an object that will contain our Keyword_Nodes.
-- It is a container that uses an AVL tree structure to hold the data.
Keyword_Table : Keyword_Trees.AVL_Tree;
procedure Clear_Keywords is
begin -- Clear_Keywords
Keyword_Trees.Clear(Keyword_Table);
end Clear_Keywords;
function Is_Empty return boolean is
begin -- Is_Empty
return Keyword_Trees.Is_Null(Keyword_Table);
end Is_Empty;
function Number return natural is
begin -- Number
return Keyword_Trees.Extent(Keyword_Table);
end Number;
procedure Insert(
Keyword : in string;
ID : in ID_Type) is
Keyword_Added : boolean;
begin -- Insert
Keyword_Trees.Insert(Keyword_Table,
Keyword_Node'(To_Unbounded_String(Keyword), ID),
Keyword_Added);
end Insert;
function Exists(Keyword : in string) return boolean is
begin -- Exists
return Keyword_Trees.Is_Member(Keyword_Table,
Keyword_Node'(To_Unbounded_String(Keyword), Unknown_ID));
end Exists;
function Identify(Keyword : in string) return ID_Type is
ID : ID_Type := Unknown_ID;
Found : boolean;
procedure Get_ID(Item : in out Keyword_Node) is
begin -- Get_ID
ID := Item.ID;
end Get_ID;
procedure Find_Node is new Keyword_Trees.Access_Actual_Item(Get_ID);
begin -- Identify
Find_Node(Keyword_Table,
Keyword_Node'(To_Unbounded_String(Keyword), Unknown_ID),
Found);
return ID;
end Identify;
procedure Put_Keywords is
function Keyword_Image(Item : in Keyword_Node) return string is
begin -- Keyword_Image
return "(" & To_String(Item.Keyword) & "," & ID_Type'image(Item.ID) & ")";
end Keyword_Image;
procedure Put_Tree is new Keyword_Trees.Print(Keyword_Image);
begin -- Put_Keywords
Put_Tree(Keyword_Table);
end Put_Keywords;
end Keyword_Manager;
with Ada.Command_Line;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants;
with Keyword_Manager; use Keyword_Manager;
procedure KM_Test is
Keyword_File : File_Type;
Buffer : string(1..1024);
Last : natural;
i, j : natural;
ID : ID_Type := Known_ID;
begin -- KM_Test
if Ada.Command_Line.Argument_Count = 1 then
Open(Keyword_File, In_File, Ada.Command_Line.Argument(1));
Clear_Keywords;
while not End_Of_File(Keyword_File) loop
Get_Line(Keyword_File, Buffer, Last);
if Last in Buffer'range then
i := Buffer'first;
loop
Find_Token(Buffer(i..Last), Letter_Set, Ada.Strings.Inside, i,
j);
exit when j = 0;
Insert(Buffer(i..j), ID);
if ID = Yet_Another_ID then
ID := Known_ID;
else
ID := ID_Type'succ(ID);
end if;
i := natural'succ(j);
exit when i > Last;
end loop;
end if;
end loop;
Close(Keyword_File);
if Is_Empty then
Put_Line("Keyword container is empty.");
else
Put_Line("There are" & natural'image(Number) &
" items in the keyword container.");
New_Line(2);
Put_Line("Contents of the keyword container are as follows:");
Put_Keywords;
New_Line(4);
loop
Put("Enter keyword to look up: ");
Get_Line(Buffer, Last);
exit when Last not in Buffer'range;
if Exists(Buffer(1..Last)) then
Put_Line("""" & Buffer(1..Last) &
""" is in the keyword container and its ID is " &
ID_Type'image(Identify(Buffer(1..Last))) & ".");
else
Put_Line("""" & Buffer(1..Last) &
""" does not exist in the keyword container!");
end if;
end loop;
end if;
end if;
end KM_Test;
^ permalink raw reply [relevance 5%]
* Re: avl tree - booch components
@ 2001-09-10 21:52 5% ` Jeffrey D. Cherry
2001-09-10 21:53 5% ` Jeffrey D. Cherry
1 sibling, 0 replies; 35+ results
From: Jeffrey D. Cherry @ 2001-09-10 21:52 UTC (permalink / raw)
I once created the following package and driver program for a colleague.
It was derived from a much larger project where we used an AVL tree as
part of a symbol table for a FORTRAN parser. It compiles with GNAT v3.13p
under Windows 2000 and the August 19, 2001 version of the Booch components.
Though comments are somewhat sparse, there is some explanation regarding
instantiating the AVL tree. Hope this helps.
--
Regards,
Jeffrey D. Cherry
Senior IV&V Analyst
Logicon Operations and Services
Logicon Inc.
a Northrop Grumman company
-- This is a simple package to store "keywords" and an associated data
-- item as an abstract data object. We'll refer to this abstract data
-- object simply as the keyword container.
package Keyword_Manager is
-- This is a dummy type so we can associate some kind of data with
-- a key field. The dummy type can, of course, be very complex if
-- it is appropriate for the problem. It could also be a generic
-- parameter. For that matter, the "key" type (strings in this
-- example) could be a generic parameter as well. I won't do that
-- here since too many levels of generic instantiations will detract
-- from what I'm trying to show.
type ID_Type is (Unknown_ID, Known_ID, Another_ID, Yet_Another_ID);
-- Clear the keyword container of all (keyword,ID) pairs so that we
-- have an empty keyword container.
procedure Clear_Keywords;
-- Return true if the keyword container is empty and return false
-- if there are one or more (keyword,ID) pairs in the keyword container.
function Is_Empty return boolean;
-- Return the number of (keyword,ID) pairs in the keyword container.
function Number return natural;
-- Insert a keyword and its associated data into the keyword container.
-- If the keyword already exists, then the ignore the data. (Normally
-- we would want to signal some kind of fault - perhaps via an exception.
-- However, we don't want to focus on error processing in this example.)
procedure Insert(
Keyword : in string;
ID : in ID_Type);
-- Return true if the given keyword exists in the keyword container and
-- return false if it does not exist in the keyword container.
function Exists(Keyword : in string) return boolean;
-- Return the ID associated with the given keyword. If the keyword
-- doesn't exist in the keyword container, then Unknown_ID is returned.
-- (Again, this should probably raise an exception but we're not
-- focusing on error processing.)
function Identify(Keyword : in string) return ID_Type;
-- Write the contents of the keyword container to standard output.
-- Normally we would want to make this ability much more flexible,
-- but we make another concession for a simple example.
procedure Put_Keywords;
end Keyword_Manager;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Strings.Maps.Constants;
with BC.Containers.Trees.AVL.Print;
with BC.Support.Unmanaged_Storage;
package body Keyword_Manager is
-- A node for the keyword table. This is the information stored in
-- the AVL tree. We use unbounded strings since we don't know the
-- length of our key strings. If we did, we could use the bounded
-- form from Ada.Strings.Bounded.
type Keyword_Node is
record
Keyword : Unbounded_String := Null_Unbounded_String;
ID : ID_Type := Unknown_ID;
end record;
-- Eventually, we'll need some kind of storage management for the
-- Keyword_Node structures and the tree that stores the data. For
-- this example, we don't care too much about storage issues, so we'll
-- use the default unmanaged storage provided by the Booch components.
subtype Tree_Storage_Pool is BC.Support.Unmanaged_Storage.Pool;
Tree_Storage : Tree_Storage_Pool;
-- Equality function used to identify equivalent nodes in the AVL tree.
-- Notice that the test is case insensative.
function Same_Keyword(Left, Right : in Keyword_Node) return boolean is
use Ada.Strings.Maps.Constants;
begin -- Same_Keyword
return Translate(Left.Keyword, Lower_Case_Map) =
Translate(Right.Keyword, Lower_Case_Map);
end Same_Keyword;
-- Ordering function used to order nodes in the AVL tree. Notice that
-- the nodes are in reverse alphabetical order and are case insensative.
function Is_Before(Left, Right : in Keyword_Node) return boolean is
use Ada.Strings.Maps.Constants;
begin -- Is_Before
return Translate(Left.Keyword, Lower_Case_Map) >
Translate(Right.Keyword, Lower_Case_Map);
end Is_Before;
-- First create an abstract container that can hold our Keyword_Nodes and
-- can test for two identical Keyword_Nodes.
package Keyword_Containers is
new BC.Containers(Item => Keyword_Node, "=" => Same_Keyword);
-- Since an abstract tree is just another form of an abstract container,
-- we create an abstract container that uses an abstract tree structure.
-- No new information is required to be given to the abstract tree
-- container and so this is just a simple instantiation built off our
-- previous container.
package Keyword_Container_Trees is new Keyword_Containers.Trees;
-- Now we must define a substantial form for the abstract tree container.
-- This is where we decide to use an AVL form of a tree rather than some
-- other form (e.g., binary or multiway). Since a tree stores data in
-- an ordered fashion, we must tell the AVL tree how to order our data.
-- This is done with the ordering function we defined above (function
-- Is_Before). This will also be our concrete package that must deal
-- with both allocation and deallocation of memory resources for the
-- tree nodes.
package Keyword_Trees is
new Keyword_Container_Trees.AVL(
"<" => Is_Before,
Storage_Manager => Tree_Storage_Pool,
Storage => Tree_Storage);
-- Okay, we can now define an object that will contain our Keyword_Nodes.
-- It is a container that uses an AVL tree structure to hold the data.
Keyword_Table : Keyword_Trees.AVL_Tree;
procedure Clear_Keywords is
begin -- Clear_Keywords
Keyword_Trees.Clear(Keyword_Table);
end Clear_Keywords;
function Is_Empty return boolean is
begin -- Is_Empty
return Keyword_Trees.Is_Null(Keyword_Table);
end Is_Empty;
function Number return natural is
begin -- Number
return Keyword_Trees.Extent(Keyword_Table);
end Number;
procedure Insert(
Keyword : in string;
ID : in ID_Type) is
Keyword_Added : boolean;
begin -- Insert
Keyword_Trees.Insert(Keyword_Table,
Keyword_Node'(To_Unbounded_String(Keyword), ID),
Keyword_Added);
end Insert;
function Exists(Keyword : in string) return boolean is
begin -- Exists
return Keyword_Trees.Is_Member(Keyword_Table,
Keyword_Node'(To_Unbounded_String(Keyword), Unknown_ID));
end Exists;
function Identify(Keyword : in string) return ID_Type is
ID : ID_Type := Unknown_ID;
Found : boolean;
procedure Get_ID(Item : in out Keyword_Node) is
begin -- Get_ID
ID := Item.ID;
end Get_ID;
procedure Find_Node is new Keyword_Trees.Access_Actual_Item(Get_ID);
begin -- Identify
Find_Node(Keyword_Table,
Keyword_Node'(To_Unbounded_String(Keyword), Unknown_ID),
Found);
return ID;
end Identify;
procedure Put_Keywords is
function Keyword_Image(Item : in Keyword_Node) return string is
begin -- Keyword_Image
return "(" & To_String(Item.Keyword) & "," & ID_Type'image(Item.ID) & ")";
end Keyword_Image;
procedure Put_Tree is new Keyword_Trees.Print(Keyword_Image);
begin -- Put_Keywords
Put_Tree(Keyword_Table);
end Put_Keywords;
end Keyword_Manager;
with Ada.Command_Line;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants;
with Keyword_Manager; use Keyword_Manager;
procedure KM_Test is
Keyword_File : File_Type;
Buffer : string(1..1024);
Last : natural;
i, j : natural;
ID : ID_Type := Known_ID;
begin -- KM_Test
if Ada.Command_Line.Argument_Count = 1 then
Open(Keyword_File, In_File, Ada.Command_Line.Argument(1));
Clear_Keywords;
while not End_Of_File(Keyword_File) loop
Get_Line(Keyword_File, Buffer, Last);
if Last in Buffer'range then
i := Buffer'first;
loop
Find_Token(Buffer(i..Last), Letter_Set, Ada.Strings.Inside, i,
j);
exit when j = 0;
Insert(Buffer(i..j), ID);
if ID = Yet_Another_ID then
ID := Known_ID;
else
ID := ID_Type'succ(ID);
end if;
i := natural'succ(j);
exit when i > Last;
end loop;
end if;
end loop;
Close(Keyword_File);
if Is_Empty then
Put_Line("Keyword container is empty.");
else
Put_Line("There are" & natural'image(Number) &
" items in the keyword container.");
New_Line(2);
Put_Line("Contents of the keyword container are as follows:");
Put_Keywords;
New_Line(4);
loop
Put("Enter keyword to look up: ");
Get_Line(Buffer, Last);
exit when Last not in Buffer'range;
if Exists(Buffer(1..Last)) then
Put_Line("""" & Buffer(1..Last) &
""" is in the keyword container and its ID is " &
ID_Type'image(Identify(Buffer(1..Last))) & ".");
else
Put_Line("""" & Buffer(1..Last) &
""" does not exist in the keyword container!");
end if;
end loop;
end if;
end if;
end KM_Test;
^ permalink raw reply [relevance 5%]
* Re: How to do case conversion?
@ 1996-08-11 0:00 5% ` Robert Dewar
1 sibling, 0 replies; 35+ results
From: Robert Dewar @ 1996-08-11 0:00 UTC (permalink / raw)
Mike Shen said
"I am trying to do case conversion in GNAT. Does anyone
know a simple way to do it? I expected the Ada.Strings(.Maps)
package to provide something for my purpose, but it doesn't."
Well this is an Ada 95 question, not a GNAT question. The standard
library routine Ada.Strings.Maps.Constants has exactly what you need,
and what you might consider is how next time you can find that more
easily than having to wait for someone to reply to you on a newsgroup.
A simple method I find useful (you can obviously do better with fancy
tools) is simply to grab a copy of the ASCII version of the RM, and
search it with your favorite editor.
I happened to know the answer to that question off the top of my head,
but if I had not, I would have searched for Lower_Case, and found the
reference in the RM almost immediately.
^ permalink raw reply [relevance 5%]
* Re: How to do case conversion?
@ 1996-08-11 0:00 5% ` Robert Dewar
0 siblings, 0 replies; 35+ results
From: Robert Dewar @ 1996-08-11 0:00 UTC (permalink / raw)
David Hoos points out that Ada.Characters.Handling contains ready made
routines that use the maps in Ada.Strings.Maps.Constants, and yes, you
may as well use them if they fit. The coding is quite trivial:
function To_Lower (Item : in Character) return Character is
begin
return Value (Lower_Case_Map, Item);
end To_Lower;
function To_Lower (Item : in String) return String is
Result : String (1 .. Item'Length);
begin
for J in Item'Range loop
Result (J - (Item'First - 1)) := Value (Lower_Case_Map, Item (J));
end loop;
return Result;
end To_Lower;
It is Lower_Case_Map that is the difficult part! Note that in Ada 95 days
it is better if you can to always use this map rather than the old
add/subtract 32 ASCII trick, since that way your code work fine for
all Latin-1 letters without any extra effort on your part, and indeed
in an implementation with localizations of these packages for other
Latin sets, your code will still work.
^ permalink raw reply [relevance 5%]
* Re: Differences between RM 5.0 and 6.0
@ 1995-03-22 15:02 6% ` Norman H. Cohen
0 siblings, 0 replies; 35+ results
From: Norman H. Cohen @ 1995-03-22 15:02 UTC (permalink / raw)
In article <Mats.Weber-2003952132250001@mlma11.matrix.ch>,
Mats.Weber@matrix.ch (Mats Weber) writes:
|> I have a paper copy of version 5.0 of the Ada 95 RM. Can I use it safely
Only if you keep it away from an open flame.
|> or are there many changes from 5.0 to 6.0 (the standard) ?
But seriously, folks: Changes include the treatment of children of
generics, the addition of predefined packages like Ada.Integer_Text_IO,
and changing Ada.Strings.Constants to Ada.Strings.Maps.Constants. At
least the first two of these changes occurred after version 5.7.
Since you are already familiar with the general shape of Ada 95, I
presume you want to use the RM as a reference to look up details, so I
would definitely suggest getting the final version.
--
Norman H. Cohen ncohen@watson.ibm.com
^ permalink raw reply [relevance 6%]
Results 1-35 of 35 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
1995-03-20 20:32 Differences between RM 5.0 and 6.0 Mats Weber
1995-03-22 15:02 6% ` Norman H. Cohen
1996-08-10 0:00 How to do case conversion? Mike Shen
1996-08-11 0:00 ` David C. Hoos, Sr.
1996-08-11 0:00 5% ` Robert Dewar
1996-08-11 0:00 5% ` Robert Dewar
2001-09-07 8:16 avl tree - booch components Tony Gair
2001-09-10 21:52 5% ` Jeffrey D. Cherry
2001-09-10 21:53 5% ` Jeffrey D. Cherry
2001-12-24 13:52 Newbie question Jasbinder S Uppal
2001-12-24 20:06 ` Michal Nowak
2001-12-24 21:13 ` martin.m.dowie
2001-12-25 12:36 ` Michal Nowak
2001-12-27 14:25 ` Alfred Hilscher
2001-12-29 21:54 ` Michal Nowak
2001-12-31 17:51 ` Jasbinder S Uppal
2002-01-01 21:26 7% ` Michal Nowak
2002-06-02 16:07 config files proposal Stephen Leake
2002-06-02 21:29 ` Darren New
2002-06-02 22:16 ` Stephen Leake
2002-06-03 14:56 ` Ted Dennison
2002-06-03 16:08 ` Darren New
2002-06-04 19:55 5% ` Ted Dennison
2002-06-09 20:43 0% ` Stephen Leake
2003-06-27 13:25 conversion Robert I. Eachus
2003-06-27 18:42 7% ` conversion tmoran
2004-07-15 13:20 questions from a newbie zork
2004-07-15 13:45 6% ` Steve
2004-07-15 14:44 5% ` Georg Bauhaus
2004-10-21 17:52 7% variable lenght strings fabio de francesco
2004-10-21 23:05 0% ` Stephen Leake
2005-03-19 16:22 Ada bench Pascal Obry
2005-03-19 16:55 ` Dr. Adrian Wrigley
2005-03-19 21:32 ` Michael Bode
2005-03-20 9:20 ` Pascal Obry
2005-03-21 23:27 ` Georg Bauhaus
2005-03-22 1:16 ` Ada bench : count words Marius Amado Alves
2005-03-22 10:59 ` Dmitry A. Kazakov
2005-03-22 11:57 ` Marius Amado Alves
2005-03-22 12:17 ` Dmitry A. Kazakov
2005-03-22 12:47 ` Marius Amado Alves
2005-03-22 13:08 ` Dmitry A. Kazakov
2005-03-22 16:48 ` Marius Amado Alves
2005-03-22 17:34 ` Dmitry A. Kazakov
2005-03-27 20:14 ` jtg
2005-03-27 21:22 ` Dmitry A. Kazakov
2005-03-28 19:54 ` jtg
2005-03-28 20:56 ` Dmitry A. Kazakov
2005-03-29 12:40 ` jtg
2005-04-01 20:58 5% ` Georg Bauhaus
2005-07-01 1:22 Data table text I/O package? Randy Brukardt
2005-07-01 3:01 ` Alexander E. Kopilovich
2005-07-02 1:54 5% ` Randy Brukardt
2005-07-02 10:24 0% ` Dmitry A. Kazakov
2005-07-06 22:04 0% ` Randy Brukardt
2005-09-27 6:27 String filtering David Trudgett
2005-09-27 7:38 ` Jacob Sparre Andersen
2005-09-27 9:13 ` David Trudgett
2005-09-27 9:49 ` Dmitry A. Kazakov
2005-09-27 11:15 ` David Trudgett
2005-09-27 14:08 7% ` Georg Bauhaus
2006-10-21 1:02 6% gnat: can't find package Tim Rowe
2006-10-21 2:57 0% ` Anh Vo
2006-10-21 6:17 0% ` Jeffrey R. Carter
2006-10-21 17:03 0% ` Tim Rowe
2006-10-21 17:54 0% ` Tim Rowe
2006-11-15 22:00 Char type verification KE
2006-11-15 21:57 6% ` Georg Bauhaus
2006-11-15 23:15 0% ` KE
2007-04-02 6:13 STORAGE_ERROR : EXCEPTION_STACK_OVERFLOW andrew.carroll
2007-04-02 10:10 ` Stephen Leake
2007-04-02 14:11 3% ` andrew.carroll
2008-03-30 17:13 6% ANN: Some updates Dmitry A. Kazakov
2012-04-03 2:11 Checking to see is a string is a letter deuteros
2012-04-03 7:09 6% ` Thomas Løcke
2012-06-11 21:55 Practicalities of Ada for app development Adam Beneschan
2012-06-12 21:12 ` Nomen Nescio
2012-06-13 0:04 ` Adam Beneschan
2012-06-13 8:37 5% ` Georg Bauhaus
2015-06-01 13:08 5% OpenToken: Parsing Ada (subset)? Jacob Sparre Andersen
2015-06-02 22:12 4% ` Stephen Leake
2016-09-13 8:46 Question on bounded / unbounded strings Arie van Wingerden
2016-09-14 11:23 6% ` Arie van Wingerden
2016-09-14 12:57 6% ` Arie van Wingerden
2018-03-01 0:27 CONSTRAINT ERROR? access check failed Mehdi Saada
2018-03-01 8:07 ` Niklas Holsti
2018-03-01 12:44 5% ` Mehdi Saada
2023-02-22 16:34 6% wait does not perform as expected Daniel Gaudry
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox