
------------------------------------------------------------
--        Name: Alden Dima
--      E-mail: dimaaa@seas.gwu.edu
--      School: The George Washington University
--              School of Engineering and Applied Science
--              Washington, D.C.
--       Class: CSci 298 - Independent Study
--     Project: Ada Curses Binding and Textual User Interface
--        File: userdoc.txt
--        Date: 12/29/95
-- Description: User Documentation for Ada Textual Interface
--              and Curses Binding
--    Revision: 5/31/96 - AAD - Modified to reflect changes
--              in the Ada-Curses binding and in AdaTUI/
--              TUIDemo.
------------------------------------------------------------

DISCLAIMER: This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.


Contents
--------

   Installing and Using AdaTUI
   AdaTUI Files
   Introduction
   Creating the Ada-Curses Binding
   Implementing AdaTUI
   Conclusions


Installing and Using AdaTUI
---------------------------

The software created for this project was developed using the GNU NYU
Ada Translator (version 3.04) running under MS-DOS and is intended for
MS-DOS GNAT users.  GNAT (GNU NYU Ada Translator) is a front-end and
run-time system for Ada 95 that uses the GCC or DJGPP (D.J. Delorie's
DOS GCC port) back-end as a code generator.  It is GNU software and
distributed under the GNU "copyleft".  GCC is the C compiler associated
with the GNU environment under development by the Free Software
Foundation.

As a convenience to the user, a beta version of PDCurses 2.3 is included
with AdaTUI.

To install AdaTUI and PDCurses:

1.  Copy adatui.zip to the directory in which you want to install AdaTUI
    and PDCurses.  Unzip adatui.zip using Info-Zip's unzip.exe or a
    compatible program.  Two directories will be created, one for
    AdaTUI, the other for PDCurses.

2.  The PDCurses library archive and header files must be made
    accessible to gcc.  The simplest way to accomplish this is to:

    a.  Copy curses.h, curspriv.h and panel.h from the PDCurses
        directory to gcc's include directory (which is typically,
        c:\gcc\include).

    b.  Copy libpano.a and libcurso from PDCurses' dos\lib directory to
        gcc's lib directory (which is usually c:\gcc\lib).

3.  Follow instructions below to create all the necessary object and
    executable files.

4.  Create all required object and executable file using the makefile
    provided.  Typing "make all" at an MS-DOS command prompt will cause 
    make to build all of the files associated with AdaTUI. The makefile 
    can be easily modified to handle new user-developed programs.

    Note: make.exe is part of the GNAT distribution and is typically
    found in \gcc\bin.  A batch file "build.bat" has been also included
    with the AdaTUI distribution and can be used instead to create the
    executable files.

AdaTUI itself is a parameterless generic package that is instantiated in
a user program in the same scope were the menu-driven procedures are
declared (see tuidemo.adb).  This guarantees that Ada's access type
scoping rules are satisfied.


AdaTUI Files (contained in adatui.zip)
--------------------------------------

Demo program for AdaTUI:
   tuidemo.adb "tuidemo.adb"

Package body and spec for AdaTUI:
   adatui.adb "adatui.adb"
   adatui.ads "adatui.ads"
 * Demo program uses AdaTUI via calls to this package's subprograms.

AdaTUI Subprograms:
   adadomen.adb "adatui-do_menu.adb"
   adathotk.adb "adatui-hotkey.adb"
   adatidle.adb "adatui-idle.adb"
   adatrmli.adb "adatui-rmline.adb"
   adbodmes.adb "adatui-body_message.adb"
   adcolbox.adb "adatui-color_box.adb"
   aderrmes.adb "adatui-error_message.adb"
   adgetstr.adb "adatui-get_strings.adb"
   adinicol.adb "adatui-init_color.adb"
   admaimen.adb "adatui-main_menu.adb"
   admakcha.adb "adatui-make_charv.adb"
   admendim.adb "adatui-menu_dimension.adb"
   adpadstr.adb "adatui-pad_string.adb"
   adprestr.adb "adatui-prepad_string.adb"
   adreedbo.adb "adatui-repaint_edit_box.adb"
   adremame.adb "adatui-repaint_main_menu.adb"
   adrepmen.adb "adatui-repaint_menu.adb"
   adsetcol.adb "adatui-set_color.adb"
   adstamen.adb "adatui-start_menu.adb"
   adstames.adb "adatui-status_message.adb"
   adtitmes.adb "adatui-title_message.adb"
   adwiedst.adb "adatui-win_edit_string.adb"
   adwiinbo.adb "adatui-win_input_box.adb"
 * Each of these files contains the body of one of the longer
   subprograms declared in adatui.ads.

Ada-Curses Binding:
   pdcurses.ads "pdcurses.ads"
   pdcurses.adb "pdcurses.adb"
   macros.c     "macros.c"
 * Uses pragma interface to bind to the curses C functions.

Variable-length strings and related operations:
   bstrings.ads "bstrings.ads"
 * Instantiation of bounded strings for use by AdaTUI.

Ada definitions of C predefined types:
   c.ads "c.ads"
 * Defines "C-style" data types to interface with types used in curses
   functions.

Integer IO Package:
   integeio.ads "integer_io.ads"
 * Instantiation of text_io.integer_io for integer types.

Bit-wise logical operations:
   twiddle.adb  "twiddle.adb"
   twiddle.ads  "twiddle.ads"
   twidunsi.ads "twiddle_unsigned.ads"
   twid.c       "twid.c"
 * Implements bit-wise logical operations in C that are accessible
   from Ada.


Introduction
------------

Because of Ada's DoD/embedded systems origins, relatively few
user-interface libraries have been written for Ada users.  The one of
the goals of this project was to produce a partial Ada binding to the
C-based curses screen manipulation library.  Curses is a UNIX library of
C functions for controlling terminal screen display from programs
written in C.  It improves program portability by providing terminal
independence - that is a single C program can correctly control the
display screen of hundreds of different terminals each with different
control codes.  Curses works by using the entries in a UNIX database
(termcap or terminfo) that contains the control codes for hundreds of
popular terminals.  The functionality of curses has been replicated
outside of the UNIX environment and is now available for MS-DOS and
other PC-based operating systems via Public Domain Curses (PDCurses
version 2.3 beta was used in this project).

The Ada curses binding would allow Ada users to enjoy the some of the
same benefits that C users derive from curses.  One of Ada's many
strengths is its ability to interface with subprograms written in other
programming languages.  For example the following curses library
function is declared in the curses header file as:

    extern WINDOW *initscr();

Ada can interface with the C function so that the programmer sees:

    function initscr return A_WINDOW_T;

by using the following compiler directive:

    pragma Import(C, initscr, "initscr");

and by properly defining the type A_WINDOW_T.  This means that Ada
programmers can transparently call the curses C functions in their
programs once all the necessary declarations in the curses header file
have been properly translated into an Ada package specification.

The Ada curses binding then allowed the porting of an existing
text-based user interface written in C (TUI) to Ada.  Textual User
Interface (TUI) version 1.02 was created by K. J. Kunst and included as
sample C code with PDCurses version 2.3.  A demonstration program
(TUIDemo) was also included.  TUI implements a basic user interface that
includes functions for pull-down menus and input boxes.  Its
functionality can be quickly incorporated into user programs.  TUIDemo
uses TUI to demonstrate the use of pull-down menus and to implement a
simple file browser that can prompt a user for a file name.  The Ada
version of TUI (AdaTUI) implements all of TUI's functionality for Ada
programs.  Table 1 shows how the components of AdaTUI-based program are
related.


                        Layer                Language
             --------------------------    ------------

                     Application               Ada
                 (e.g. tuidemo.adb)

                   User Interface              Ada
               (adatui.ads/adatui.adb)

                   Curses Binding              Ada
               (pdcurses.ads/pdcurses.adb)

              curses library functions          C
                    (libcurso.a)


           Table 1. Basic structure of programs using AdaTUI.


Creating the Ada-Curses Binding
-------------------------------

Because of its size, a hand conversion of curses.h into a Ada package
specification would have been tedious.  Fortunately, a tool exists
(cbind - available from ftp://rational.com/public/tools/cbind) that
greatly simplifies the translation C header files into Ada.  The Ada
output generated by cbind will usually not compile without modification.
However, significantly less effort is required to "fix" the cbind
generated code than to create a C binding by hand.  The cbind makefile
was written to run under UNIX and calls a C-shell script, and did not
run properly under MS-DOS.   Rather than rewrite the makefile, cbind was
compiled under Solaris and the conversion of the PD Curses header file
took place there.

In order to use cbind, a package (c.ads) must be created that declares
C-style data types in Ada   An example c.ads for an Ada 83 compiler is
provided with cbind.  To take advantage of enhanced Ada 95 interfacing
features, c.ads was rewritten to use the types found in interfaces.c.
For example, instead of defining C-style character arrays and pointers
as either:

     type charp is access character;
or
     type charv is array(natural) of character;
     type charp is access charv;

they were instead implemented as:

     subtype char  is interfaces.c.char;
     subtype charv is interfaces.c.char_array;
     type    charp is access all interfaces.c.char_array;

This redefinition simplified interfacing to the curses functions.

Unfortunately, cbind could not handle the curses functions defined as
pseudofunctions.  Attempts to force macro expansion caused cbind to
crash.  Many of the curses pseudo-functions also exist in compiled form
within the library to simplify debugging.  This means that in principle,
they could be called from Ada if the appropriate function declarations
and compiler directives are added to the curses binding.  However, to
guarantee that all necessary curses functions would always be callable
by an Ada program, the pseudofunctions required for AdaTUI were
implemented in Ada by creating "wrapper" functions that "expanded" the
macro definition.  For example, the pseudofunction addch, which adds a
character to the standard screen, is defined by the following macro:

#define addch( c )              waddch( stdscr, c )

It was implemented in Ada as:

   function addch ( ch : chtype ) return c.signed_int is
   begin
      return waddch ( stdscr, ch );
   end addch;

The Ada wrapper functions were placed into an Ada '95 child package
(curses.macros) to simplify maintenance should future versions of curses
be translated by cbind.

The curses library functions require the use of bit-wise logical
operations to create some of the parameters that are passed to certain
functions.  Packed Boolean arrays are necessary to efficiently implement
bit-wise logical operations in Ada.  Unfortunately GNAT does not yet
implement packed arrays.  An attempt was made to implement the bit-wise
logical operations using record representation clauses but it was
discovered that the resulting code was too cumbersome: each bit had a
unique (non-indexable) identifier.  As a result, the necessary bit-wise
logical operations were implemented in C and then interfaced to Ada.  A
generic package (twiddle) was created which allowed instantiation for
all Ada and C integer-sized types.  This package used pragma import
allow access to the C code.


Implementing AdaTUI
-------------------

For the most part, AdaTUI faithfully follows the structure of TUI.  The
main focus of the project was interfacing Ada with C code to implement a
non-trivial mixed Ada/C system with practical value.  Little was done to
re-engineer TUI to take full advantage of Ada's features.

Yet the fact that good-sized C program could be easily translated into
Ada 95 without significantly changing its structure is in itself
exciting.  C is often heralded as a most flexible language.  Much of its
power appears to be related to its use of pointers.  Ada '83 pointers
can only point to dynamic objects allocated from the heap; C-style
pointers to subprograms are not possible.  Among the many new language
features implemented in Ada '95 are pointers that can point to declared
objects and subprograms.  These new pointers are used extensively
in AdaTUI, especially to dispatch subprograms from the pull-down menus.
This means that much of the flexibility of C is available in Ada 95,
with the additional advantages of Ada's strong type checking, more
readable syntax, better support for modularity, and built-in safety
features.  One important consequence was that AdaTUI was developed with
very little need for debugging tools.  Another was that it was very easy
to use Ada's package facility to create the layered structure between
the application program that uses AdaTUI and the underlying curses
library functions (Table 1).

At early stages of the project, it was hoped that AdaTUI could be
implemented by gradually "eroding" away the C source code.  This means
that at first AdaTUI would be implemented as a "wrapper" package that
provided an Ada interface to TUI.  A user program such as tuidemo could
then be written in Ada and call the C functions in TUI.  Subsequent
versions of AdaTUI would replace increasing amounts of C code with
corresponding Ada.  It soon became apparent that this would not be
possible since the operation of TUI involves passing a pointer to a
function from the tuidemo program to lower-level routines in TUI.  These
pointers are dereferenced when a menu item is invoked.  The C-compiled
code was not able to properly dereference the access values for Ada
subprograms even when using pragma convention with the subprogram access
types.  This meant that TUI would have to be entirely rewritten in Ada.

In addition, there were problems because of Ada's access value lifetime
rules, which do not allow an access value to point to a subprogram in
another separately compiled package.  This was resolved by implementing
AdaTUI as a generic package so that it could be instantiated in the same
scope as the menu-driven procedure in the user application.  (Note: GNAT
2.04 does not strictly implement Ada's rules for access values - GNAT
2.07 for Solaris was used to to verify that access types were being
properly used).

Another issue was which operating systems would be targeted by AdaTUI
and how multiple targets would be handled.  C source code typically
handles the question of multiple targets by a heavy reliance on the
preprocessor.  As a result, the source for several targets can co-exist
in interwoven fashion in a single source file.  This gives the C
programmer the illusion of having a platform independent source file.
Even though AdaTUI compiles without error under Solaris, there are
operating system dependencies that prevent it from executing properly.
Because Ada does not have a preprocessor, multiple AdaTUI targets could
have been handled by:

     Hiding the environment-specific features in a package, and creating
     a different version of the package for each target.  Because of the
     way TUI was written, this would effectively mean a different
     version of AdaTUI for each environment.

     Using conditional statements to decide which block of code to
     execute depending on the value of certain global constants,
     possibly located in a separate package.  Each environment would
     have a different set of values.  This would mean that for each
     environment, AdaTUI would contain "dead code" that would increase
     the executable size.  In addition, the conditional statements would
     slow down execution and make maintenance and debugging much more
     interesting.

In order to keep the project manageable, it was decided that since the
majority of the AdaTUI users would most likely be MS-DOS users, only an
MS-DOS version would be created at first.  Versions of AdaTUI for
different environments could be ported later if necessary.

As work on AdaTUI and TUIDemo progressed, compilation time became
excessively long and the TUIDemo executable size surprisingly large
(>500 Kb).  The culprit was discovered to be GNAT's implementation of
Ada 95 bounded strings - instantiation can take several minutes and
produce more than 200Kb of object code.  AdaTUI Compilation time was
greatly improved by moving the instantiation code to a separate file
(bstrings.ads) and performing the instantiation once.  Unfortunately,
the TUIDemo executable size remains large.


Conclusions
-----------

This project demonstrated that is it relatively easy to create an Ada
interface to a C library and to translate relatively complex C source
directly into Ada.  Despite the successful implementation of the partial
Ada-Curses binding and AdaTUI, there exist several areas with room for
improvement.

One problematic area is the binding of Ada to C-pseudofunctions.  Though
a conservative approach might suggest that bindings should only be
provided for "true" C functions, different implementation of curses
could differ in their choice of functions to be implemented as
preprocessor macros.  For the most part, the actual method of
implementation makes little difference to the C programmer.  However,
the Ada-Curses binding would lack portability because some functions
previously coded in C might now be implemented via macros.  A possible
solution would be to define a "standard" curses interface and to
implement it in C.  This interface would serve as a new layer between
the curses functions and the Ada-Curses binding.  Every curses function
would be called via a wrapper function in the interface.  Unfortunately,
this would tend to reduce execution speed by increasing the function
call overhead.

Another area needing improvement is the handing the C-style data types
in Ada.  These data types appeared in the curses binding, AdaTUI, and
TUIDemo.  Their appearance in the higher layers, make AdaTUI and
programs that use it less readable.  This could be remedied by writing a
package that contains Ada wrapper functions for the Ada-Curses binding
that take "native" Ada types as parameters and perform conversions
between the Ada and C-style data types.  This would also add to the
function call overhead, however Ada's pragma inline could be used to
mitigate the decrease in execution speed.  Both concerns mentioned above
suggest that a "thick" Ada-Curses binding would be better than the
current "thin" binding.

The use of Ada's bounded strings facility results in large executable
files and long compilation times.  These might be improved if a
different variable-length string implementation (such as Ada's unbounded
strings) were used.

Ada has a much richer set of language features than C and as a result
changes are necessary to take full advantage of Ada's power.  Both the
binding and AdaTUI need modification to support program's using Ada's
concurrent programming features.  The main concern is that the C window
data structure be properly protected against competitive access by
concurrent tasks.  This would most likely be implemented using Ada 95's
protected type feature, although in principle, semaphores implemented
via tasks could also be used.

Another possibility would be to make future Ada-Curses binding and
AdaTUI more modular and object-oriented.  Rather than implement the
binding as a single large package for the C functions and a child
package for the pseudofunctions, a core set of curses data structures
and functions could be made part of a parent package.  Additional less-
used features could be migrated into several small child packages.  If
an object-oriented approach were used, the curses binding and AdaTUI
could be reorganized into a collection of objects.  Both would consist
of several packages, each implementing an object.
