Callable FIGARO

Keith Shortridge, AAO

28th April 1995


1. Introduction

The system described as "Callable Figaro" provides a means of running a programmed sequence of Figaro commands that is faster and, generally speaking, easier to program than command language procedures or shell scripts. It is important to note that it is not intended to be any more than a means of sequencing operations performed by Figaro.

The basic concept is very simple; a Fortran (or any other high level language) program may be written that passes Figaro commands as character arguments to a subroutine called FIGARO. The resulting program may then be compiled, linked, and run. The Callable Figaro system will perform the commands just as does the ordinary Figaro system, but without the overhead of having to start up a new image for each command.

For example, the following program uses Callable Figaro to set the hard copy graphics device and plot the spectrum of the data in the file MYSPECT.DST

C Example program 1

C

CALL FIGARO ('HARD PRI')

CALL FIGARO ('SPLOT MYSPECT HARD RESET \')

CALL FIGARO_CLOSE

END

A single command is provided to compile and link such simple programs. If the above program is in the file PLOTIT.FOR, then the command

FIGLINK PLOTIT

will compile the program, link it with the callable Figaro system, and define the command PLOTIT so that it invokes it. That, in essence, is all there is to Callable Figaro. In practice, of course, there are a number of additional points that need to be covered in order to make full use of the system. In the following description of the Callable Figaro system, `FIGARO' will refer to the subroutine, and `Figaro' will be used to refer to the system.

2. Opening and Closing the System

The call to FIGARO_CLOSE at the end of the example program shown in the introduction is required to ensure that the system -and in particular, the variables file- is closed down properly. It should be included at the end of all Callable Figaro programs. If it is called without the system having been started at all, that doesn't matter; there are internal flags to indicate the state of the system, which is why, although there is a corresponding routine called FIGARO_OPEN, it need not be called explicitly. However, although the system can tell that it has not been called previously -and so needs to initialise itself- it has no way of knowing that it will not be called again and so needs to shut itself down.

3. Controlling the Command Strings

The most obvious limitation of the program shown in the introduction is that the command string is fixed; it always plots MYSPECT, and it always resets the plotting parameters before it does it. That, after all, is what the command

SPLOT MYSPECT HARD RESET \

is supposed to do. One way around this should be obvious to any Fortran programmer reading this; clearly, the argument to the routine FIGARO is nothing more than a Fortran character variable, and Fortran provides a host of means to manipulate such character strings. For example, the following program is rather more flexible than the one in the previous section (although it should not be copied, for reasons to be explained later in the section on error handling)

C Example program 2

C

CHARACTER COMMAND*80,SPECT*16

DO WHILE (.TRUE.)

PRINT *,'Spectrum:'

READ (*,'(A)',END=500) SPECT

COMMAND='SPLOT '//SPECT//' HARD RESET \'

CALL FIGARO (COMMAND)

END DO 500 CONTINUE

CALL FIGARO_CLOSE

END

In the above example, if the string input by the user in response to the `Spectrum:' prompt is MYSPECT, then the string generated in COMMAND using the string concatenation operator (//) is:

`SPLOT MYSPECT HARD RESET \'

the extra spaces coming from the fact that SPECT was declared as being 16 characters long. This, as far as Figaro is concerned, is just the same as the command in the previous example.

Readers, especially those brought up on versions of Fortran that precede the introduction of the CHARACTER type, may find they need to review the use of character strings in Fortran 77. Balfour and Marwick (Programming in Standard Fortran 77) are quite good on the subject, although the Fortran provided by VAXes and most modern UNIX systems -- which generally support most of the VAX Fortran extensions -- is a little more flexible in what it allows than is the standard Fortran they describe. For example, these Fortrans will allow free-format writes to character strings, which is useful but non-standard. However, as should become clear, the FIGARO routine itself provides a couple of tricks that may help.

Consider a slightly different version of the previous program:

C Example program 3

C

CHARACTER SPECT*16

DO WHILE (.TRUE.)

PRINT *,'Spectrum:'

READ (*,'(A)',END=500) SPECT

CALL FIGARO ('SPLOT ',SPECT,' HARD RESET \')

END DO 500 CONTINUE

CALL FIGARO_CLOSE

END

This in fact works in just the same way, but the concatenation of the three character strings to produce the single Figaro command string is performed by the FIGARO routine itself. FIGARO will take any number of character arguments and will concatenate them into one string, so the command string that would result if SPECT were to have the value `MYSPECT' would be

`SPLOT MYSPECT HARD RESET \'

which is just what we had before, except that when FIGARO concatenates its string arguments it removes leading and trailing blanks from each argument and then inserts just one blank between each pair of arguments. This is why the spacing in the command generated here seems more natural than that from the previous example. In some cases, of course, you don't want the program to do that, and ways round it will be described later.

On a VAX, FIGARO can take up to 255 strings as arguments, but none of them can be more than 256 characters long (including trailing blanks), and the final concatenated command string (with the unnecessary blanks removed) must itself be no more than 256 characters long. None of these restrictions should prove a problem in practice. These restrictions do not apply to the UNIX version.

If the command as passed omits parameters, these will be prompted for in the normal way.

4. Numeric and Logical Arguments

Manipulating character strings is all very well, but in many cases the things in the Figaro commands that we want to vary will be numbers. For example, the ICADD command adds a constant to an image, and has the syntax

ICADD image constant resulting_image

So we might imagine a Callable Figaro program that performs an ICADD command, using Fortran to generate a command string as follows:

C Example program 4

C

CHARACTER COMMAND*80,IMAGE*16

REAL VALUE

DO WHILE (.TRUE.)

PRINT *,'Image:'

READ (*,'(A)',END=500) IMAGE

PRINT *,'Number:'

ACCEPT *,VALUE

WRITE (COMMAND,'(A,A,1PE13.6,1X,A)')

: 'ICADD ',IMAGE,VALUE,IMAGE

CALL FIGARO (COMMAND)

END DO 500 CONTINUE

CALL FIGARO_CLOSE

END

The internal formatted write statement used here is perfectly standard Fortran 77, and will work perfectly well, but is rather messy to code. If the image is specified as MYIMAGE and the number as 1000 then the command string generated will be

`ICADD MYIMAGE 1.000000E+03 MYIMAGE'

Note that the 1X format item is needed to separate the number from the second image name.

The Callable Figaro system provides three functions that make this sort of program easier to code. These are character functions (something that very few people seem to make much use of, but quite standard), called CF, CI, and CL, that return a string containing respectively, a formatted real number, integer, or logical value. Because they are functions returning character strings, they can be used as arguments in a call to FIGARO. The names have been chosen purely in the interests of conciseness. CF can be used to simplify the previous example as follows:

C Example program 5

C

CHARACTER CF*16

CHARACTER IMAGE*16

REAL VALUE

DO WHILE (.TRUE.)

PRINT *,'Image:'

READ (*,'(A)',END=500) IMAGE

PRINT *,'Number:'

ACCEPT *,VALUE

CALL FIGARO ('ICADD',IMAGE,CF(VALUE),IMAGE)

END DO 500 CONTINUE

CALL FIGARO_CLOSE

END

Note that CF has had to be declared as being of type CHARACTER. The actual length used in the declaration is unimportant so long as it is long enough. The minimum lengths for CF,CI and CL are in fact 13, 11 and 3 respectively, but it's easiest just to call them all 16, which is easier to remember. The command that will be generated here is

`ICADD MYIMAGE 1000 MYIMAGE'

since CF will actually use an integer format if it can, rather than the messy Fortran E format. If the number were to be specified as 123.4567 the command generated would be

`ICADD MYIMAGE 1.234567E+03 MYIMAGE'

The use of CI should be obvious. Do note, however, that whether you use CI or CF depends solely on the type of Fortran variable (as declared in your program) that you pass as an argument. The type of the Figaro parameter that it will represent in the final command is irrelevant; indeed, there is no necessary one-to-one correspondence between arguments passed to FIGARO (the subroutine) and the parameters finally used by the Figaro application.

The use of CL may not be quite so obvious, since not many people seem to make use of the Figaro syntax that allows keywords to be specified as, for example in SPLOT,

SPLOT ERASE=YES AXES=NO \

rather than as just

SPLOT ERASE NOAXES \

However, given that, a section of Fortran code using Callable Figaro might contain the following:

C Example program 6

C

CHARACTER*16 CF,CL

CHARACTER SPECT*16

REAL HIGH, LOW

LOGICAL ERASE,AXES

.....................

code that sets SPECT, HIGH, LOW, AXES and ERASE

.....................

CALL FIGARO ('SPLOT',SPECT,'HIGH',CF(HIGH),'LOW',CF(LOW), : 'ERASE=',CL(ERASE),'AXES=',CL(AXES))

CALL FIGARO_CLOSE

END

CL simply returns either `YES' or `NO', depending on the value of its argument.

5. Omitting Spaces Between Arguments

Sometimes, you want to use two or more FIGARO arguments to produce a single command parameter. In this case, you do not want them to be separated by spaces in the resulting command string. For example, suppose you have a sequence of spectra called SPECT1,SPECT2 etc up to SPECT10, and want to run EXAM to display their .Z structures. You cannot just use

C Bad Example program 7

C

CHARACTER CI*16

DO I=1,10

CALL FIGARO('EXAM SPECT',CI(I),'.Z')

END DO

CALL FIGARO_CLOSE

END

because this will generate a sequence of commands of the form

`EXAM SPECT 1 .Z'

which the EXAM command will not understand correctly. (It will take it as a command to examine the structure called `SPECT' -which probably doesn't exist- with two extra parameters that mean nothing to it at all.)

FIGARO recognises the Fortran string concatenation operator (`//'), if it appears at the start or end of an argument string, as an indication that this string (without the `//') is to be butted up against the adjacent argument with no intervening blanks. The correct form for this example program is

C Example program 8

C

CHARACTER CI*16

DO I=1,10

CALL FIGARO('EXAM SPECT//',CI(I),'//.Z')

END DO

CALL FIGARO_CLOSE

END

which will generate a sequence of commands of the form

`EXAM SPECT1.Z'

as required. There is even, occasionally, a case for using an argument which is just `////' to pull together the two arguments on either side, as in, for example,

C Example program 9

C

CHARACTER CI*16

CHARACTER STRUCT*2

STRUCT='.Z'

DO I=1,10

CALL FIGARO('EXAM SPECT//',CI(I),'////',STRUCT)

END DO

CALL FIGARO_CLOSE

END

which produces just the same sequence of commands as does example 8.

6. Handling Errors

In general, when you write a program that executes a series of Callable Figaro commands, you expect every one of them to work, and you want the program to stop prematurely if one of them fails. This is in fact what will happen in all the previous examples. If a Figaro error occurs during a call to FIGARO, an internal error flag is set and all subsequent calls to FIGARO will be ignored (it will return immediately, without attempting to execute the command it has been passed).

So, for example, if the files SPECT1.DST through SPECT4.DST existed, but SPECT5.DST had been deleted, then example programs 8 and 9 in the previous section would get as far as SPECT4, would fail on SPECT5, and then call subsequent calls to FIGARO would be ignored, irrespective of whether or not the files SPECT6.DST through SPECT10.DST existed.

This raises two questions, both simply answered: how do you find out if a Figaro error has occurred, and how do you clear the error condition? To answer the first, we reveal that FIGARO is in fact written as a function rather than as a subroutine (under the VMS and compatible compilers, a function may be CALLed if the calling program doesn't care about the returned function value, and this has been the case in all the examples so far). The function value returned is an integer, and is zero to indicate OK, and non-zero (at present always 1, but this may change in the future) to indicate an error. To clear an error, the subroutine FIGARO_CLEAR is provided. This has no arguments, and clears any existing Figaro error condition, allowing normal execution to continue. Error messages will be output by the Figaro application programs as always, so there is usually no need for the calling program to explicitly indicate that FIGARO returned an error status.

So example 8 might be better coded as:

C Example program 10

C

CHARACTER CI*16

INTEGER FIGARO,STATUS

DO I=1,10

STATUS=FIGARO('EXAM SPECT//',CI(I),'//.Z')

IF (STATUS.NE.0) CALL FIGARO_CLEAR

END DO

CALL FIGARO_CLOSE

END

Or, more easily, since there is no harm in calling FIGARO_CLEAR even if no error has occurred,

C Example program 11

C

CHARACTER CI*16

DO I=1,10

CALL FIGARO('EXAM SPECT//',CI(I),'//.Z')

CALL FIGARO_CLEAR

END DO

CALL FIGARO_CLOSE

END

Sometimes it is convenient to be able to determine the status of the Callable Figaro system directly, rather than having to code your program so that it always remembers the status returned by the last call to FIGARO. The integer function FIGARO_STATUS returns the current error status of the Callable Figaro system. This will normally be the same as the value returned by the last call to the routine FIGARO, although if FIGARO_CLEAR has been called it will return zero. So another alternative would be

C Example program 12

C

INTEGER FIGARO_STATUS

CHARACTER CI*16

DO I=1,10

CALL FIGARO('EXAM SPECT//',CI(I),'//.Z')

IF (FIGARO_STATUS().NE.0) CALL FIGARO_CLEAR

END DO

CALL FIGARO_CLOSE

END

7. Keeping Track of the Commands Being Executed

Since the calls to FIGARO can sometimes get a little complex, it is often worth being able to find out just what commands are being generated. Also, it can be handy sometimes just to be able to keep track of how far an executing program has got. For this, the routine FIGARO_VERIFY is provided.

FIGARO_VERIFY has one argument, and this is a single logical value. If this is true, all commands as generated by FIGARO will be logged on the normal output device before being executed, and this will continue until either the program finishes or there is another call made to FIGARO_VERIFY with an argument whose value is false. In this context, `true' and `false' have their Fortran meanings, the least significant bit of the value being clear to indicate `false' and set to indicate `true'.

If you need to determine whether or not the verify state is on or not, you can use FIGARO_VERIFY as a logical function. Used in this way it returns the current state -ie the state before the call was made- as the function value. So if you simply want to see if the verify state was set, but do not want to change it, you can use the following code:

C Example program 13

C

LOGICAL STATE,FIGARO_VERIFY

...................

STATE=FIGARO_VERIFY(.TRUE.)

IF (STATE) PRINT *,'Verify state set'

STATE=FIGARO_VERIFY(STATE)

...................

which determines the current state, setting it true -temporarily- and then returning it to that previous setting.

8. Figaro User Variables

The LET statement is available under Callable Figaro just as it is normally, but a couple of shortcuts are provided to make it easy to access Figaro user variables directly from a high level language.

The function FIGARO_GET_VALUE is used to obtain the value of a numeric user variable. If invoked as a function, it returns an integer error code whose value is zero if the user variable existed and its numeric value was obtained OK. A non-zero code indicates some sort of error. So for example, given that the function ISTAT is known to set the user variables STAT_MIN and STAT_MAX, the following code will plot a spectrum scaled to give 10% headroom (this code also demonstrates the use of FIGARO_VERIFY to display the commands being passed to the Callable Figaro system):

C Example program 14

C

CHARACTER*16 CF

REAL HIGH,LOW

CALL FIGARO_VERIFY(.TRUE.)

CALL FIGARO('ISTAT MYSPECT RESET \')

CALL FIGARO_GET_VALUE('STAT_MAX',HIGH)

CALL FIGARO_GET_VALUE('STAT_MIN',LOW)

HIGH=HIGH+(HIGH-LOW)*0.1

CALL FIGARO('SPLOT MYSPECT RESET HIGH=',CF(HIGH),

: 'LOW=',CF(LOW),'\')

CALL FIGARO_CLOSE

END

Similarly, the function FIGARO_GET_CHAR(name,string) will return the value of a Figaro character user variable. User variables may also be set by the functions FIGARO_SET_VALUE and FIGARO_SET_CHAR. Both of these will set the value of a user variable of the appropriate type, creating such a variable if it does not in fact exist. No equivalent routines to access array variables have been supplied in the current release of the system.

For example, the defaults for HIGH and LOW could be set using FIGARO_SET_VALUE, to produce the following program:

C Example program 15

C

CHARACTER*16 CF

REAL HIGH,LOW

CALL FIGARO('ISTAT MYSPECT RESET \')

CALL FIGARO_GET_VALUE('STAT_MAX',HIGH)

CALL FIGARO_GET_VALUE('STAT_MIN',LOW)

HIGH=HIGH+(HIGH-LOW)*0.1

CALL FIGARO_SET_VALUE('HIGH',HIGH)

CALL FIGARO_SET_VALUE('LOW',LOW)

CALL FIGARO('SPLOT MYSPECT \')

CALL FIGARO_CLOSE

END

9. Linking

To make the linking of simple programs easier, the command FIGLINK has been defined, as shown in the introduction. This not only compiles and links a program that uses Callable Figaro, it also defines the program name as a command that runs the program, no matter what you reset your default directory to. This will only work for programs that do not need any additional libraries.

If you need to include additional libraries, the way this has to be done differs from system to system.

9.1. UNIX

The UNIX implementation of FIGLINK allows additional libraries, object modules, even compile flags such as `-g' to be included following the name of the program to be linked, eg:

figlink myprog myroutine.o mylibrary.a

9.2. VMS

A program using Callable Figaro needs to be linked with a shareable image called BIGFIG. This is best achieved by including in the link command a reference to FIGARO_PROG_S:BIGFIG.OLB/LIB. For example, if you have a fortran program called PLOTIT.FOR in your current default directory, you can compile and link it using:

$FOR PLOTIT

$LINK PLOTIT,FIGARO_PROG_S:BIGFIG.OLB/LIB

and then run it in the obvious way, using

$RUN PLOTIT

Obviously, if PLOTIT uses any special libraries, these will have to be included explicitly in your link command. The .EXE files produced are quite small: all of the example programs shown here need fewer than ten blocks.

10. Use in Batch Mode

Callable Figaro programs may be used in batch mode in just the same way as the ordinary Figaro programs.

Under UNIX, a batch job is really just a program run with an ampersand at the end of the command line and left to run to completion. This means that it normally includes all the path settings, aliases etc of the shell that invokes it. However, you should check that your .cshrc file -- which will be executed by the batch program if it is a shell program run by `csh' or any of its kin such as `tcsh' -- does not reset the path to something that does not include the Figaro directories.

Under VMS the only thing to watch is that the `Figaro' command should appear in the batch file before either a normal Figaro program or a Callable Figaro program is run. The `Figaro' command is needed to set up logical names and symbols needed by both types of Figaro programs. Most of the comments to be found in the documentation concerned with the normal use of Figaro in batch mode under VMS apply to Callable Figaro, especially the section on testing of procedures.

11. Limitations

As was said earlier, Callable Figaro is only intended as a means of programming sequences of Figaro commands, and its use should be restricted to this. Programmers should resist the temptation to include direct calls to the DTA_ package, for example, in an attempt to mix processing performed by Callable Figaro and operations performed explicitly on Figaro data files. Use of any of the packages used by the Figaro routines (SGS/GKS, PGPLOT, the PAR_ and VAR_ packages) may lead to all sorts of complications. More detailed guidelines may emerge, but for the moment the safest thing is not to get over ambitious in the use of this system.

Some of the Figaro programs, particularly the earlier ones, were not really written with this sort of environment in mind, and -although it is thought that most routines have been coded properly, in this respect- some may not always release all the resources they use, particularly in those cases when errors occur. If programs with a great many repetitive FIGARO calls, particularly ones that error, fail through lack of virtual memory, or with quota exceeded faults, this should be reported and the programs made less ambitious in scope. At least until the application programs in question have been fixed.

Callable Figaro can only be used for those standard Figaro applications that are known to the FIGARO subroutine. If you have your own Figaro programs you cannot run them through calls to the FIGARO subroutine, unless you link a new version that includes your routines. Although this is not difficult, it is not yet documented how to do it.

You can always execute your own Figaro applications through a subroutine call that spawns off (forks) a new process to run an individual program. Under VMS this would be a call to LIB$SPAWN, under UNIX it can be done using routines such as `system' -- unfortunately, `system', like most UNIX system routines, is intended to be called from C. It is possible to write a simple Fortran-callable wrap-up for `system' on a UNIX machine, however.

12. Summary of Callable Figaro Routines

CHARACTER*(*) FUNCTION CF (VALUE)

CHARACTER*(*) FUNCTION CI (IVALUE)

CHARACTER*(*) FUNCTION CL (LVALUE)

INTEGER FUNCTION FIGARO (STRING,STRING2,....STRINGn)

INTEGER FUNCTION FIGARO_GET_VALUE (NAME,VALUE)

INTEGER FUNCTION FIGARO_GET_CHAR (NAME,STRING)

INTEGER FUNCTION FIGARO_SET_VALUE (NAME,VALUE)

INTEGER FUNCTION FIGARO_SET_CHAR (NAME,STRING)

LOGICAL FUNCTION FIGARO_VERIFY (STATE)

INTEGER FUNCTION FIGARO_STATUS ()

SUBROUTINE FIGARO_CLEAR

SUBROUTINE FIGARO_CLOSE

SUBROUTINE FIGARO_OPEN

Where LVALUE and STATE are logical values, NAME and STRING1 .. STRINGn are character strings, VALUE is a single precision floating point value and IVALUE is an integer. Logical and integer and real values here should be four byte quantities

13. References

Balfour A., Marwick D.H.; 1979, "Programming in Standard Fortran 77", Heinemann Educational Books, London.