Getting Started | Documentation | Glish | Learn More | Programming | Contact Us |
Version 1.9 Build 1556 |
|
During the prototype stage a basic command line user interface was build, with which tasks have been constructed. Some work was spend in showing that both the AIPS interpreter and the Graphical User Interface (GUI) are plug-in compatible user interfaces. For example, a functional GUI for Khoros4.1 is available for demo purposes. The AIPS shell interpreter can be thought of in terms of the Miriad4.2 shell interpreter.
The basic (command line) user interface is a series of ``keyword=value'' pairs, which we call program parameters4.3.
The class Param (see Param.h) implements one single such parameter. In addition to a name and a value, a parameter has a variety of other attributes, such as a one-line help string (useful when being prompted etc.), a type, a range and optional units. All of these are character strings; parsing and error checking is done at a different level. The programmer however will never interact with a parameter through it's class interface. This is done with the class Input, which is some kind of container of Param's, with a variety of user interface attributes (help-level, message/debug-level etc).
Although the programmer must supply the user interface with a number of predefined program parameters, the user interface itself will create a small number of system parameters (help=, debug=). The purpose of these is to tell the task how to communicate with the user and it's environment, and give the user control over these items. For example, the user may want to be prompted, with error recovery, and see (debug) messages above a certain threshold level.
For the benefit of the Programmer, the user interface also defines a number of standard parameters (``templates''), which can be copied and bound to a program parameter.
Parameter names are to be found by minimum match, if so requested by the user.
Most programs are probably happy with a simple set of parameters, like a linear list. We have discussed hierarchical keywords and in Section 4.3 a few thoughts are expressed.
All input as well as output is controlled by the user interface. The Astronomer has a varying degree of control over how and where input and output occurs. In the command line interface system control occurs through a small number of system parameters, which can be preset by environment variables, supplied as if they were parameters on the command line, or both.
For example, a interactive UNIX shell session may look like:
1% setenv DEBUG 1 2% setenv HELP prompt,aipsenv 3% prog key1=val1 key3=val3 4% prog val1 val2 key4=val4 key5=val5 debug=0 5% unsetenv HELP DEBUG 6% prog help=pane > prog.pane
After having preset the DEBUG and HELP modes in commands 1% and 2%, commands 3% and 4% will act accordingly: the user is prompted, and parameter default values are restored and saved from an AIPS environment file before and after invocation. In addition, in command 4% the user decided not to see any messages. Command 6% gives an example of the self-describing mode of programs, where a pane description file for Khoros has been constructed.
No, we don't want you to use main(int argc, char **argv) anywhere in your code. Instead, use aips_input(), aips_main() and aips_output().
To summary, your section of code could then look something like:
//aips++ // Hypothetical Silly Interactive Contour Plotter // #include <Main.h> // Standard declarations needed for an AIPS++ main program #include <SillyImage.h> aips_input(Input &inputs) // Definition of the allowed Program Parameters { inputs.Version("19-mar-92 PJT"); inputs.Usage("Hypothetical Silly Interactive Contour Plotter"); inputs.Create( "in", "", "Input file", "InFile", "r!"); inputs.Create( "levels", "", "Contour levels", "RealArray"); inputs.StdCreate("lstyle", "lstyle", "solid", "My Contour line type"); inputs.StdCreate("lwidth"); inputs.Create( "annotate","full", "What annotation?", "String", "full|brief|none|publication"); inputs.StdCreate("device"); } aips_main(Input &inputs) // Computation box - this could be spawned to various machines { String dname = inputs.GetString("device"); Device device(dname); do { File f = inputs.GetFile("in"); RealArray contours = inputs.GetRealArray("levels"); String lstyle = inputs.GetString("lstyle"); Int lwidth = inputs.GetInt("lwidth"); contours.Sort(); // Make sure this array is sorted if(contours.Count() > 20) cwarning << "A lot of contours buddy\n" if(countour.Count() == 0) break; cdebug.Level(1); cdebug << "Plotting " << contours.count() << " contours\n" << Level(2) << contours << "\n"; SillyImageContour(f.name(),contours.Count(),contours.Value(), lstyle, lwidth, dname); } while (inputs.More()); device.Close(); }
Comments:
The aips_input routine could be automatally made by a code generator from a description section encoded in the source code of the program itself, much like Mark Calabretta`s proposal discussed last fall. The advantage of this is that we can generate more elaborate online context and level dependant help. It should not be too hard to create readable documents in page description languages like man, latex or texinfo. The Andrew Toolkit, which has been considered too, is a different story.
A number of standard ostream's (cwarning, cerror and cdebug) are to be provided for4.4, acting much like cerr; they handle warning messages, fatal error messages and a (Astronomer controlable message level) debug output. After a fatal error the program will exit gracefully. A specified number of fatal errors can be overridden by a system parameter (error=). The Programmer can also define a cleanup function, say aips_cleanup, which is called before the program really quits. Even a recover function could be supplied with which Programmers can recover from a known localized fatal error.
#include <stdarg.h> void error(char *fmt ...); void warning(char *fmt ...); void debug(int level, char *fmt ...);
#include <Main.h>
.
A hierarchical parameter would be set using the format
key.class1.class2.class3=value
(e.g. ``xaxis.grid.style=dotted'') we will use a notation where the hierarchical level is given by a the appropriate number of dots that the keyname starts with. To start with an example, a somewhat elaborate program which would clearly benefit from hierarchical keywords
<Key> <StdKey> <Type> <Range> ==== ======== ====== ======= in infile InFile r|w|w!|rw|..... .region xyzselect String contour bool t|f .levels RealArray sort($0,$N) .style lstyle String solid|dotted|dashed|.... .thickness lwidth int 0:5 .color color String cyan|red|green|0x134|.... greyscale bool t|f .minmax Real[2] $1<$2 .gamma Real >=0 .invert bool t|f .colormap colormap InFile bw|rainbow|.. xaxis .ticks Real[2] .grid Real ..style lstyle ..thickness lwidth .label String ..font font InFile (calcomp|helvetica|roman)(10,12,15,20) yaxis .ticks Real[2] .grid Real ..style lstyle ..thickness lwidth .label String ..font font InFile (helvetica|roman)(10,12,15,20) annotate String none|brief|full|publication
Comments/Problems:
Range must contain a boolean expression, where $0
is the
name of an array, $N
the number of elements, $1
,
$2
, $3
, ... $($N)
the array elements, &
and
|
the boolean operators, :
to denote an implied do-loop
(with optional second :
followed by the stride). A fairly
rich syntax will be made available.
File could be the same as a String but could also be usefull class (InFile and OutFile) in itself, with name, file pointer? and appropriate wildcard expansion of the string into the full filename.
xaxis,yaxis: these two keywords are clearly related. In prompt mode it would be annoying if the Astronomer sat through the whole xaxis family, and then wants to do the yaxis tree with the defaults now inherited from the xaxis tree. (perhaps only the label name would be different (though the most appropriate default would be the one from the image header, if available). The programmer must leave the defaults in yaxis blank, and take the xaxis equivalent if none supplied in the yaxis equivalent.