comp.lang.ada
 help / color / mirror / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* 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