Ada95 Binding for ncurses
The ncurses Ada95 binding is © 1996 by
Jürgen Pfeifer.
Permission is hereby granted to reproduce and distribute this
binding by any means and for any fee, whether alone or as part
of a larger distribution, in source or in binary form, PROVIDED
this notice is included with any such distribution, and is not
removed from any of its header files. Mention of ncurses and the
author of this binding in any applications linked with it is
highly appreciated.
This binding comes AS IS with no warranty, implied or expressed.
General Remarks
- Although I like Ada95 very much (thanks to GNAT),
I'm not really a poweruser of it, because at work we don't use it :-(.
So I can use it only at home for my small private projects :-).
So any comments of the real Ada Gurus about design flaws are really
appreciated.
- This document describes Version 00.91 of the binding.
- The functionality is modelled to be compatible with the ncurses
package, a clone of the SVr4 curses model.
I did the development on an Intel box running
Linux 1.3.x and 2.0,
ncurses-1.9.9g and the
GNU Ada Translator
gnat-3.05. For any older versions of ncurses and gnat
it will not work.
- You must have the m4 macroprocessor to build this package.
If you don't have this program, you can get the FSF version
here.
- Ada programs are supposed to be readable. One of my
favourite methods to make code readable is to use expressive
names for the identifiers. You can find a list of a mapping
of the cryptic curses names to the Ada names in this table.
- This is not a typical one-2-one interface mapping. It is
close to one-2-one on the functional level. Each (n)curses function
has it's counterpart with a more or less similar formal parameter list
in the binding. I make use of Ada's overloading mechanisms. This means,
that sometimes different C functions are represented by the same
Ada procedure/function name, but with different formal parameter lists.
The mapping is not one-2-one with respect to the datatypes.
I tried to make records out of the flat chtype and similar structures,
so you don't have to do bit operations to mark an attributed character
as bold. Just make the boolean member bold of the record
true. The binding also hides the structures like WINDOW, PANEL, MENU, FORM
etc. !
- I try to do as much error checking as possible and feasible
in the binding. I will raise an Ada exception when something
went wrong in the low-level curses. This has the effect that - at least
first time in my life - (n)curses programs have now a very rigid error
checking, but - thanks to Ada - you don't have to code the orgiastic
error checking style of C.
- Support for wide characters is currently not in the binding, as it
is not really in ncurses at this point in time.
Directory organization and the build process
The toplevel directory of the Ada95 binding contains only the README,
TODO and the Makefile. All the rest are subdirectories containing
various parts of the binding. All of this is configured during the
configure process of the ncurses package, as long as the configure
script detects the right version of GNAT. It must be 3.05 or above.
The subdirectories are
Directory | Content |
gen | Generation templates and Generator |
html | Documentation in HTML format |
ada_include | Binding specification and body files |
ada_objects | Binding object files (after compilation) |
objects | Temporary object files created during compilation |
samples | Sample programs for the binding. |
The top level Makefile first visits the gen directory and makes the
targets there. The main purpose of this directory is to create and run a helper program
named gen. gen is compiled with the current headers and libraries
of this ncurses package. It is used to generate various constants and data structures
into several Ada95 package specifications. Several ncurses datatypes are int's used
as bitmaps. To model this as Ada95 records, one has to provide a representation clause
that guarantees the correct mapping, because this depends on the endianess of the
machines architecture.
The gen program is called with two single letters as argument and generates then
output depending on the arguments on the standard output channel. This output is
then included into the various template files by the m4 macroprocessor.
The templates all have the name pattern terminal_*.m4. If you cut the .m4 extension you
have the names of the files that are generated.
For more details which letter combinations are allowed as arguments, about there meanings
and how the output is merged into the templates please consult the sourcefile gen.c and the
Makefile in the gen directory.
You should never edit the generated sources. Use the templates and run the
generator again.
After the generation of the specifications, the ada_include directory is entered. This
now contains the complete library source for the Ada95 binding to ncurses. The make in
this directory now creates the associated object files and linker information files in
the ada_objects directory.
Finally the samples directory is entered. There is currently only one sample program.
The executables name is tour. The purpose of the sample is simply to
give a coding sample for the binding and not so much to provide a demo of all ncurses
features.
Limitations
- I provide no SCREEN datatype and functions to set a new screen.
If you need this (mostly for debugging I guess), write a small
C routine doing all this and import it into your Ada program.
- I provide no functions to switch on/off curses tracing options.
Same suggestion as above.
- Although Ada95 is an OO Language, this binding doesn't provide
an OO abstraction of the (n)curses functionality. As mentioned above
it's a thin binding for the (n)curses functions. But without any
doubt it would be nice to build on top of this an OO abstraction
of (n)curses functionality.
- If you use the user-pointer mechanism for most of the ncurses
structures in a mixed language environemt, i.e. Ada95 and C routines
operate on the same objects, care must be taken because the Ada
binding itself uses the user pointer mechanism for it's own purposes.
See the corresponding section in implementention
details.
- I currently do not support the link_fieldtype functionality of the
forms subsystem.
- The *_IO packages are currently output only.
Installation
After you have successfully built the whole ncurses package including
this binding, you will find in the Ada95 directory two subdirectoried:
You can copy them to the place were you usually store your ada libraries
or just leave them here. You have to use the -p option
of the cp command. You have to add these directories to the
ADA_INCLUDE_PATH or ADA_OBJECTS_PATH environment variables.
If you use the --srcdir option when configuring your ncurses, the
ada_include directory is actually splitted across two directory trees.
One ada_include directory is part of the Ada95 subtree of the ncurses
source tree. It contains those package specifications and bodies which
are not generated on the fly. In the Ada95 subdirectory of your build
tree you'll find the other part of ada_include, which contains those
specfications and bodies that are generated. You must copy both
subdirectories into one common target directory where you store your
GNAT libraries.
If you perform the install step of the ncurses global Makefile (or
the install.libs step), a library named libncwrap.a will be installed
in your selected library target directory. This is a tiny C wrapper
library required by the binding to encapsulate a few functions of
(n)curses. We plan to integrate these wrappers into the ncurses main
library so that this wrapper is no longer required in the future.
Hierarchy of packages
Implementation Details
Behind the abstraction
All the new types like Window, Panel,
Menu, Form etc. are just
opaque representations of the pointers to the corresponding
low level (n)curses structures like
WINDOW *, PANEL *,
MENU * or FORM *.
So you can safely pass them to C routines that expect a pointer
to one of those structures.
Item and Field Arrays
In C you have to pass the item and field arrays to define menus or forms
terminated by a null item or null field. This is not necessary in this
binding. The binding routines will construct from an Ada95 style array
of Item or Field objects internally the properly terminated array of
C structure pointers. See the examples for more details.
Extended ripoffline() usage
The official documentation of (n)curses says, that the line parameter
determines only whether or not exactly one line is
stolen from the top or bottom of the screen. So essentially only the
sign of the parameter is evaluated. ncurses has internally implemented
it in a way, that uses the line parameter also to control the amount of
lines to steal. This mechanism is used in the Rip_Off_Lines
routine of the binding.
User Pointer mechanism
TBD
How user defined field types work
TBD
Enumeration fields handling
The (n)curses documentation says, that the String arrays to be passed to
an TYPE_ENUM fieldtype must not be automatic variables. This is not true
in this binding, because it is internally arranged to safely copy these
values.
Using other Ada compilers
This should basically not be a problem, but you have to replace a code
sequence in the package body of
Terminal_Interface.Curses.Forms
that uses a hashing package supplied with the GNAT runtime, which is not part
of the Standard Ada runtimes. This should not be too hard. I intend to remove
this dependency in the future.
Port to other curses implementations
Basically it should not be too hard to make all this run on a regular SVr4
implementation of curses. The problems are probably these:
- ncurses has some additional features which are presented in this binding. You
have two choices to deal with this:
- Emulate the feature in this binding
- Raise an exception for non implemented features
Most likely you will follow a mixed approach. Some features are easy to simulate,
others will be hard if not impossible.
- For menu items, the name and descriptions are internally copied by ncurses.
So the binding doesn't care for the lifetime of the strings passed to the
construction routine for items. This assumption is not true in most other implementations
of the menu library. In this case you have to modify the binding routine
New_Item to safestore the strings.
I'm quite sure I forgot something.