aboutsummaryrefslogtreecommitdiff
path: root/sys/imfort/doc/imfort.ms
diff options
context:
space:
mode:
Diffstat (limited to 'sys/imfort/doc/imfort.ms')
-rw-r--r--sys/imfort/doc/imfort.ms1711
1 files changed, 1711 insertions, 0 deletions
diff --git a/sys/imfort/doc/imfort.ms b/sys/imfort/doc/imfort.ms
new file mode 100644
index 00000000..cc0c1919
--- /dev/null
+++ b/sys/imfort/doc/imfort.ms
@@ -0,0 +1,1711 @@
+.RP
+.TL
+A User's Guide to Fortran Programming in IRAF
+.br
+The IMFORT Interface
+.AU
+Doug Tody
+.AI
+.K2 "" "" "*"
+September 1986
+
+.AB
+The IMFORT interface is a Fortran programming environment suitable for general
+Fortran programming, with special emphasis on batch image processing.
+IMFORT is intended for use primarily by the scientist/user who occasionally
+needs to write a program for their own personal use, but who does not program
+often enough to make it worthwhile learning a larger, more complex but fully
+featured programming environment. IMFORT is therefore a small interface which
+is easy to learn and use, and which relies heavily upon host system (non-IRAF)
+facilities which the user is assumed to already be familiar with.
+Facilities are provided for accessing command line arguments, reading and
+writing IRAF images, and returning output to the CL. Provisions are made
+for editing, compiling, linking, and debugging programs without need to leave
+the IRAF environment, making use of familiar host system editing and debugging
+tools wherever possible.
+.AE
+
+.NH
+Introduction
+.PP
+The IMFORT interface is a library of Fortran callable subroutines which can
+be called from a host system Fortran program to perform such operations as
+fetching the arguments given on the command line when the task was invoked,
+or accessing the header or pixel information in an IRAF image (bulk data frame).
+Since the result is a host program rather than an IRAF program, only limited
+access to the facilities provided by the runtime IRAF system is possible,
+but on the other hand one has full access to the facilities provided by the
+host system. Programs which use IMFORT may be run as ordinary host system
+programs outside of IRAF, or may be interfaced to the IRAF command language
+(CL) as CL callable tasks. Within the IRAF environment these user written,
+non-IRAF tasks behave much like ordinary IRAF tasks, allowing background
+execution, use of i/o redirection and pipes, evaluation of expressions on
+the command line, programmed execution in scripts, and so on.
+
+.NH 2
+Who Should Use IMFORT
+.PP
+The most significant feature of the IMFORT interface is that it is designed
+for use by \fIhost\fR Fortran programs. The scientist/user will often already
+be using such programs when IRAF becomes available. IMFORT allows these
+pre-existing programs to be modified to work within the IRAF environment
+with a minimum of effort and with minimum changes to the existing program.
+The only alternative is to rework these programs as \fIIRAF\fR programs,
+but few existing Fortran programs could (or should) survive such a transition
+without being completely rewritten. If the program in question is useful
+enough such a rewrite might be warranted, but in most cases this will not
+be practical, hence something like the IMFORT interface is clearly needed
+to keep these old programs alive until they are no longer needed.
+.PP
+The second goal of the IMFORT interface is to provide a way for the user to
+add their own programs to IRAF without having to invest a lot of time learning
+the full blown IRAF programming environment. IMFORT makes it possible for
+the user to begin writing useful programs within hours of their first exposure
+to the system. It is possible that the IMFORT interface will provide all the
+capability that some users will ever need, especially when supplemented by other
+(non-IRAF) Fortran callable libraries available on the local host machine.
+Programs developed in this way are bound to have portability and other
+problems, but it should be up to the developer and user of the software to
+decide whether these problems are worth worrying about. IMFORT is simply
+a \fItool\fR, to be used as one sees fit; there is no attempt to dictate to
+the user how they should write their programs.
+.PP
+The alternative to IMFORT, if applications programming within IRAF is the goal,
+is the IRAF SPP/VOS programming environment. The SPP/VOS programming
+environment is a fully featured scientific programming environment which
+carefully addresses all the software engineering issues avoided by IMFORT.
+The VOS is a large and complex environment and therefore takes longer to learn
+than IMFORT, but it provides all the facilities needed by large applications
+hence is \fIeasier\fR to use than simpler interfaces like IMFORT, if one is
+faced with the already difficult task of coding a large program or package.
+Furthermore, the SPP/VOS environment fully addresses the problems of
+portability and device independence, critical issues for applications which
+must be supported and used simultaneously on a range of machines over a
+period of years, during which time the software is likely to be continually
+evolving. An overview of the SPP/VOS programming environment is given in
+\fIThe IRAF Data Reduction and Analysis System\fR, February 1986, by the author.
+.PP
+In summary, IMFORT is intended for use to interface old Fortran programs to
+IRAF with a minimum of effort, and as an entry level programming environment
+which new users can learn to use in a few hours. Experienced users,
+professional programmers, and developers of large applications will find that
+they can accomplish more with less effort once they have learned to use the
+more fully featured SPP/VOS programming environment.
+
+.bp
+.NH
+Getting Started
+.PP
+Although programs which use IMFORT can and often will be invoked from the
+host system command interpreter, it is likely that such programs will also
+be used interactively in combination with the tasks provided by the standard
+IRAF system. For example, the IRAF graphics and image display facilities
+are likely to be used to examine the results of an image operation performed
+by a user written Fortran/IMFORT program. Indeed, the standard IRAF tasks
+are likely to be used for testing new IMFORT programs as well as reducing data
+with old ones, so we shall assume that software development will take place
+from within the IRAF environment. Since IRAF provides full access to the
+facilities of the host system at all times, there is little reason not to
+work from within the IRAF environment.
+.PP
+As a first step, let's see what is required to enter, compile, link, and
+execute a small Fortran program which does nothing more than print the
+message \fLhello, world!\fR on the terminal. We shall assume that the
+reader has read the \fICL User's Guide\fR and is already familiar with
+basic CL command entry, the OS escape facility, the editor interface and so on.
+The first step is to call up the editor to enter the program into a file:
+.DS
+\fLcl> edit hello.f\fR
+.DE
+Note that the filename extension is ".f", which is what IRAF uses for
+Fortran files. The extension will be mapped into the local host system
+equivalent when IRAF communicates with the host system, but when working
+in the IRAF environment the IRAF name should be used.
+.LP
+Once in the editor, enter the following program text:
+.DS
+\fLprogram hello
+write (*,*) 'hello, world!'
+stop
+end\fR
+.DE
+The next step is to compile and link the \fLhello\fR program. This is done
+by the command \fIfc\fR (\fIf\fRortran-\fIc\fRompile), which produces an
+object file \fLhello.o\fR and an executable program file \fLhello.e\fR.
+Note that the \fIfc\fR task is defined in the default \fIuser\fR package in
+your \fLLOGIN.CL\fR file, hence a \fImkiraf\fR may be required to regenerate
+the \fLLOGIN.CL\fR file if the file is old or has been modified.
+.DS
+\fLcl> fc hello.f\fR
+.DE
+Since the \fLhello\fR program is a host Fortran program, it can be executed
+immediately with an OS escape, e.g., \fL!hello.e\fR on UNIX, or
+\fL!run hello\fR on VMS. A better approach if the task has command line
+arguments is to use the IRAF \fIforeign task\fR facility to define the
+program as a new IRAF task, as we shall see in the next section.
+
+.NH 2
+Example 1: Plotting a function
+.PP
+As a slightly more complicated example, let's construct a program to compute
+and plot a function using command line arguments to input the function
+parameters, with output consisting of a simple ASCII table sampling the
+computed function. Our example computes the Planck function, which gives the
+emissivity of a blackbody as a function of wavelength and temperature.
+The sample program is shown in Figure 1. Source code for this and all other
+examples in this paper may be found in the IRAF directory \fLimfort$tasks\fR.
+
+.DS
+\fL
+.ps 8
+.vs 9p
+c PLANCK -- Compute the Planck blackbody radiation distribution for a
+c given temperature and wavelength region.
+c
+c usage: planck temperature lambda1 lambda2
+c
+c The temperature is specified in degrees Kelvin and the wavelength
+c region in microns (1u=10000A). 100 [x,y] data points defining the
+c curve are output.
+c ----------------------------------------------------------------------
+
+ program planck
+
+ character*80 errmsg
+ integer nargs, ier, i
+ real w1, w2, dw, cm, t
+ real xv(100), yv(100)
+
+c --- Get the temperature in degrees kelvin.
+ call clargr (1, t, ier)
+ if (ier .ne. 0) then
+ write (*, '('' temperature (degrees kelvin): '',$)')
+ read (*,*) t
+ endif
+
+c --- Get the wavelength region to be computed.
+ call clnarg (nargs)
+ if (nargs .ge. 3) then
+ call clargr (2, w1, ier)
+ if (ier .ne. 0) goto 91
+ call clargr (3, w2, ier)
+ if (ier .ne. 0) goto 91
+ else
+ write (*, '('' start wavelength (microns): '',$)')
+ read (*,*) w1
+ write (*, '('' end wavelength (microns): '',$)')
+ read (*,*) w2
+ endif
+
+c --- Compute the blackbody curve.
+ dw = (w2 - w1) / 99.0
+ do 10 i = 1, 100
+ xv(i) = ((i-1) * dw) + w1
+ cm = xv(i) * 1.0E-4
+ yv(i) = (3.74185E-5 * (cm ** -5)) /
+ * (2.71828 ** (1.43883 / (cm * t)) - 1.0)
+ 10 continue
+
+c --- Print the curve as a table.
+ do 20 i = 1, 100
+ write (*, '(f7.4, g12.4)') xv(i), yv(i)
+ 20 continue
+
+ stop
+
+c --- Error exit.
+ 91 call imemsg (ier, errmsg)
+ write (*, '('' Error: '', a80)') errmsg
+ stop
+ end\fR
+.DE
+.vs
+.ps
+.sp
+.ce
+Figure 1. Sample program to compute the Planck function\(dd
+.FS
+\(ddThe trailing \fL$\fR carriage control code used in the format strings in
+the \fLWRITE\fR statements in this and the other sample Fortran programs
+is nonstandard Fortran and may not be available on all host machines.
+Its function is to defeat the carriage-return linefeed so that the user's
+response may be entered on the same line as the prompt.
+.FE
+
+.PP
+This example serves to demonstrate the use of the IMFORT \fIclarg\fR procedures
+to fetch the command line arguments, and the use of i/o redirection to capture
+the output to generate the plot. The command line to an IMFORT program consists
+of a sequence of arguments delimited by spaces or tabs. The subroutine
+\fIclnarg\fR returns the number of arguments present on the command line when
+the task was called. The \fIclargr\fR, \fIclargi\fR, etc. procedures fetch
+and decode the values of the individual arguments. Virtually all IMFORT
+procedures include an integer output variable \fIier\fR in their argument list;
+a zero status indicates success, anything else indicates failure and the actual
+error code identifies the cause of the problem. The \fIimemsg\fR procedure
+may be called to convert IMFORT error codes into error message strings, as in
+the example.
+.PP
+Once the program has been entered and compiled and linked with \fIfc\fR,
+we must declare the program as a foreign task to the CL. If this is not
+done the program can still be run via an OS escape, but none of the advanced
+CL features will be available, e.g., background execution, command line
+expression evaluation, i/o redirection, and so on. The technique used to
+declare a foreign task is machine dependent since it depends upon the syntax
+of the host command interpreter. For example, to declare the new CL foreign
+task \fIplanck\fR on a UNIX system, we enter the following command:
+.DS
+\fLcl> task $planck = $planck.e\fR
+.DE
+The same thing can be achieved on a VMS system with the following
+declaration (it can be simplified by moving the VMS foreign task declaration
+to your \fLLOGIN.COM\fR file):
+.DS
+\fLcl> task $planck = "$planck:==\\\\$\fIdisk\fP:[\fIdir\fP...]planck.exe!planck"\fR
+.DE
+The \fL$\fR characters are required to tell the CL that the new task does
+not have a parameter file, and is a foreign task rather than a regular
+IRAF task. The \fL!\fR in the VMS example is used to delimit multiple DCL
+commands; the command shown defines the DCL foreign task \fIplanck\fR and
+then executes it. The use of the \fItask\fR statement to declare foreign
+tasks is discussed in detail in \(sc3.3.
+.PP
+We have written the program in such a way that the arguments will be queried
+for if not given on the command line, so if we enter only the name of the
+command, an interaction such as the following will occur:
+.DS
+\fLcl> planck
+temperature (degrees kelvin): 3000
+start wavelength (microns): .1
+end wavelength (microns): 4\fR
+.DE
+Note that if the output of the \fIplanck\fR task is redirected this input
+mechanism will \fInot\fR work, since the queries will be redirected along
+with the output. Hence if we use a pipe to capture the output, as in the
+following example, the arguments must be given on the command line.
+.DS
+\fLcl> planck 3000 0.1 4.0 | graph
+.DE
+This command will compute and plot the emissivity for a 3000 degree kelvin
+blackbody from 0.1 to 4.0 microns (1000 to 40000 angstroms).
+.PP
+An interesting alternative way to implement the above program would be to
+output the function curve as a line in an image, rather than as a table of
+numbers. For example, a two dimensional image could be generated wherein
+each line corresponds to a different temperature. \fIGraph\fR or \fIimplot\fR
+could then be used to plot curves or overplot families of curves; this would
+be more efficient than the technique employed in our sample program.
+Image access via IMFORT is illustrated in our next example.
+
+.NH 2
+Example 2: Compute the range of pixel values in an image
+.PP
+The program shown in Figure 2 opens the named image, examines each line in
+the image to determine the minimum and maximum pixel values, keeping a running
+tally until the entire image has been examined (there is no provision for
+detecting and ignoring bad pixels in the image). The newly computed minimum
+and maximum pixel values are then updated in the image header as well as
+printed on the standard output.
+.DS
+\fL
+.ps 8
+.vs 9p
+c MINMAX -- Compute the minimum and maximum pixel values in an image.
+c The new values are printed as well as updated in the image header.
+c
+c usage: minmax image
+c ----------------------------------------------------------------------
+
+ program minmax
+
+ character*80 image, errmsg
+ real pix(4096), dmin, dmax, vmin, vmax
+ integer im, axlen(7), naxis, dtype, ier, j
+
+c --- Get image name.
+ call clargc (1, image, ier)
+ if (ier .ne. 0) then
+ write (*, '('' enter image name: '',$)')
+ read (*,*) image
+ endif
+
+c --- Open the image for readwrite access (we need to update the header).
+ call imopen (image, 3, im, ier)
+ if (ier .ne. 0) goto 91
+ call imgsiz (im, axlen, naxis, dtype, ier)
+ if (ier .ne. 0) goto 91
+
+c --- Read through the image and compute the limiting pixel values.
+ do 10 j = 1, axlen(2)
+ call imgl2r (im, pix, j, ier)
+ if (ier .ne. 0) goto 91
+ call alimr (pix, axlen(1), vmin, vmax)
+ if (j .eq. 1) then
+ dmin = vmin
+ dmax = vmax
+ else
+ dmin = min (dmin, vmin)
+ dmax = max (dmax, vmax)
+ endif
+ 10 continue
+
+c --- Update the image header.
+ call impkwr (im, 'datamin', dmin, ier)
+ if (ier .ne. 0) goto 91
+ call impkwr (im, 'datamax', dmax, ier)
+ if (ier .ne. 0) goto 91
+
+c --- Clean up.
+ call imclos (im, ier)
+ if (ier .ne. 0) goto 91
+ write (*, '(a20, 2 g12.5)') image, dmin, dmax
+ stop
+
+c --- Error exit.
+ 91 call imemsg (ier, errmsg)
+ write (*, '('' Error: '', a80)') errmsg
+ stop
+ end\fR
+.DE
+.vs
+.ps
+.sp
+.ce
+Figure 2. Compute the min and max pixel values in an image
+
+.PP
+The program as written can only deal with images of one or two dimensions,
+of pixel type short (16 bit integer) or real (32 bit floating), with a line
+length not to exceed 4096 pixels per line. We could easily change the program
+to deal with images of up to three dimensions, but the IMFORT interface does
+not provide dynamic memory allocation facilities so there is always going
+to be an upper limit on the line length if we use the simple get line i/o
+procedure \fIimgl2r\fR, as shown. The use of fixed size buffers simplifies
+the program, however, and is not expected to be a serious problem in most
+IMFORT applications.
+.PP
+The \fIalimr\fR subroutine in the previous example is from the IRAF VOPS
+(vector operators) package. The function of \fIalimr\fR is to compute
+the limiting (min and max) pixel values in a vector of type real, the
+function type being indicated by the \fIlim\fR, and the pixel datatype by
+the \fIr\fR. The VOPS package provides many other such vector operators,
+and is discussed further in \(sc 4.4.
+
+.NH 2
+Example 3: Copy an image
+.PP
+Our final example (Figure 3) shows how to create a new image as a copy of
+some existing image. This can be used as a template to create any binary
+image operator, i.e., any program which computes some transformation upon
+an existing image, writing a new image as output.
+.PP
+By now the functioning of this procedure should be self evident.
+The only thing here which is at all subtle is the subroutine \fIimopnc\fR,
+used to open (create) a new copy of an existing image. The open new copy
+operation creates a new image the same size and datatype as the old
+image, and copies the image header of the old image to the new image.
+Any user keywords in the header of the old image will be automatically
+passed to the new image, without requiring that the calling program
+have explicit knowledge of the contents of the image header.
+.PP
+Note that the program is written to work only on pixels of type real,
+hence will be inefficient if used to copy images of type short-integer.
+A more efficient approach for a general image copy operator would be
+to add a conditional test on the variable \fLdtype\fR, executing a
+different copy-loop for each datatype, to avoid having to convert from
+integer to real and back again when copying a short-integer image.
+The short-integer equivalents of \fIimgl3r\fR (get line, 3 dim image,
+type real) and \fIimpl3r\fR (put line, 3 dim image, type real) are
+called \fIimgl3s\fR and \fIimpl3s\fR.
+.PP
+The program as written will work for images of up to three dimensions,
+even though it is written to deal with only the three dimensional case.
+This works because the length of the "unused" axes in an image is
+set to one when the image is created. A program passed an image of
+higher dimension than it is written for will also work, but will not
+process all of the data. IMFORT does not support image sections,
+so only the first few lines of the image will be accessible to such
+a program.
+
+.PP
+Additional useful examples of Fortran programs using IMFORT are given in
+\fLimfort$tasks\fR. These include utility programs to make test images,
+print the contents of an image header, print the values of the pixels in
+a subraster, and so on. You may wish to copy the source for these to your
+own workspace for use as is, or for use as templates to construct similar
+programs.
+
+.DS
+\fL
+.ps 8
+.vs 9p
+c IMCOPY -- Copy an image. Works for images of up to three dimensions
+c with a pixel type of short or real and up to 4096 pixels per line.
+c
+c usage: imcopy oldimage newimage
+c ---------------------------------------------------------------------
+
+ program imcopy
+
+ real pix(4096)
+ character*80 oimage, nimage, errmsg
+ integer ncols, nlines, nbands, j, k, oim, nim
+ integer ier, axlen(7), naxis, dtype, nargs
+
+c --- Get command line arguments.
+ call clnarg (nargs)
+ if (nargs .eq. 2) then
+ call clargc (1, oimage, ier)
+ if (ier .ne. 0) goto 91
+ call clargc (2, nimage, ier)
+ if (ier .ne. 0) goto 91
+ else
+ write (*, '('' input image: '',$)')
+ read (*,*) oimage
+ write (*, '('' output image: '',$)')
+ read (*,*) nimage
+ endif
+
+c --- Open the input image and create a new-copy output image.
+ call imopen (oimage, 1, oim, ier)
+ if (ier .ne. 0) goto 91
+ call imopnc (nimage, oim, nim, ier)
+ if (ier .ne. 0) goto 91
+
+c --- Determine the size and pixel type of the image being copied.
+ call imgsiz (oim, axlen, naxis, dtype, ier)
+ if (ier .ne. 0) goto 91
+
+ ncols = axlen(1)
+ nlines = axlen(2)
+ nbands = axlen(3)
+
+c --- Copy the image.
+ do 15 k = 1, nbands
+ do 10 j = 1, nlines
+ call imgl3r (oim, pix, j, k, ier)
+ if (ier .ne. 0) goto 91
+ call impl3r (nim, pix, j, k, ier)
+ if (ier .ne. 0) goto 91
+ 10 continue
+ 15 continue
+
+c --- Clean up.
+ call imclos (oim, ier)
+ if (ier .ne. 0) goto 91
+ call imclos (nim, ier)
+ if (ier .ne. 0) goto 91
+
+ stop
+
+c --- Error actions.
+ 91 call imemsg (ier, errmsg)
+ write (*, '('' Error: '', a80)') errmsg
+ stop
+ end\fR
+.DE
+.vs
+.ps
+.sp
+.ce
+Figure 3. Image copy program
+
+.bp
+.NH
+The IMFORT Programming Environment
+.PP
+IRAF provides a small programming environment for the development of host
+Fortran programs using the IMFORT interface. This environment consists
+of the general CL tools, e.g., the editor, the \fIpage\fR and \fIlprint\fR
+tasks, etc., plus a few special tools, namely, the \fIfc\fR compile/link
+utility and the foreign task facility. In this section we discuss these
+special tools and facilities. Information is also provided for linking
+to the IMFORT libraries if program development is to take place at the host
+system level.
+.PP
+The classic third generation program development cycle (ignoring such minor
+details as designing the software) is edit \(em compile/link \(em debug.
+The edit phase uses the CL \fIedit\fR task, an interface to the host system
+editor of choice. The compile/link phase is performed by the \fIfc\fR utility.
+The debug phase is optional and is generally only necessary for large programs.
+The host system debug tool is used; while IRAF does not provide a special
+interface to the host debug tool, one can easily be constructed using the
+foreign task facility if desired.
+.PP
+Programs which use the IMFORT interface are inevitably host system dependent
+to some degree, since they are host programs. In the interests of providing
+the user with concrete examples, the discussion in this section must therefore
+delve into the specifics of certain host operating systems. We have chosen
+to use UNIX and VMS in the examples, since most IRAF implementations run on
+one or the other of these operating systems. The ties between the IMFORT
+programming environment and the host system are quite simple, however, so it
+should not be difficult to see how to modify the examples for a different host.
+
+.NH 2
+The FC Compile/Link Utility
+.PP
+The \fIfc\fR utility provides a consistent, machine independent interface to
+the host system compiler and linker which is convenient and easy to use.
+In addition, \fIfc\fR provides a means for linking host programs with the
+IRAF libraries without having to type a lot, and without having to build
+host command scripts. All of the IRAF libraries are accessible via \fIfc\fR,
+not just IMFORT (\fLlib$libimfort.a\fR) and the IRAF system libraries used
+by IMFORT, but all the other IRAF libraries as well, e.g., the math libraries.
+.PP
+The default action of \fIfc\fR is to compile and link the files listed on the
+command line, i.e., source files in various languages, object modules, and
+libraries. Any source files are first turned into object modules, then the
+objects are linked in the order given, searching any libraries in the order
+in which they are encountered on the command line (the IMFORT libraries are
+searched automatically, after any libraries listed on the command line).
+By default, the root name of the new executable will be the same as that of
+the first file listed on the command line; a different name may be assigned
+with the \fI-o\fR switch if desired.
+.LP
+The syntax of the \fIfc\fR command is as follows:
+.DS
+\fLfc [\fIswitches\fP] \fIfile\fL [\fIfile ...\fL] [-o \fIexefile\fL]\fR
+.DE
+The most interesting switches are as follows:
+.in 0.5i
+.IP \fB-c\fR
+Compile but do not link.
+.IP \fB-l\fIlibrary\fR
+.br
+Link to the named IRAF library. On a UNIX host this switch may also be
+used to reference the UNIX libraries. The \fI-llibrary\fR reference
+should be given in the file list at the point at which you want the
+library to be searched. The \fI-l\fR causes \fIfc\fR to look in a set
+of standard places for the named library; user libraries should be
+referenced directly by the filename of the library.
+.IP \fB-o\fR\ \fIexefile\fR
+.br
+Override the default name for the executable file produced by the linker.
+.IP \fB-x\fR
+Compile and link for debugging.
+.in
+
+.LP
+Since the \fIfc\fR command line can contain many different types of objects,
+a filename extension is required to identify the object type. The IRAF
+filename extensions \fImust\fR be used; these are listed in the table below.
+
+.TS
+box center;
+cb s
+ci | ci
+c | l.
+IRAF Filename Extensions
+_
+extn usage
+=
+\.a object library
+\.c C source file
+\.e executable
+\.f Fortran source file
+\.o object module
+\.s Assembler source file
+\.x SPP source file
+.TE
+
+.PP
+The \fIfc\fR utility is easy to learn and use. Here are a few examples
+illustrating the most common usage of the utility. To compile and link the
+Fortran program \fLprog.f\fR, producing the executable program \fLprog.e\fR:
+.DS
+\fLcl> fc prog.f\fR
+.DE
+To compile the file \fLutil.f\fR to produce the object \fLutil.o\fR,
+without linking anything:
+.DS
+\fLcl> fc -c util.f\fR
+.DE
+To link \fLprog.o\fR and \fLutil.o\fR, producing the executable program
+\fLprog.e\fR:
+.DS
+\fLcl> fc prog.o util.o\fR
+.DE
+To do the same thing, producing an executable named \fLfoo.e\fR instead
+of \fLprog.e\fR:
+.DS
+\fLcl> fc prog.o util.o -o foo.e\fR
+.DE
+To compile and link \fLprog.f\fR for debugging:
+.DS
+\fLcl> fc -x prog.f\fR
+.DE
+To link \fLprog.o\fR with the IRAF library \fLlib$libdeboor.a\fR (the DeBoor
+spline package), producing the executable \fLprog.e\fR as output:
+.DS
+\fLcl> fc prog.o -ldeboor\fR
+.DE
+To do the same thing, spooling the output in the file \fLspool\fR and
+running the whole thing in the background:
+.DS
+\fLcl> fc prog.o -ldeboor >& spool &\fR
+.DE
+To link instead with the library \fLlibfoo.a\fR, in the current directory
+(note that in this case the library is a module and not a switch):
+.DS
+\fLcl> fc prog.o libfoo.a\fR
+.DE
+.LP
+Just about any combination of switches and modules that makes sense will
+work. The order of libraries in the argument list is important, as they
+will be searched in the order in which they are listed on the command line.
+.PP
+The \fIfc\fR utility is actually just a front-end to the standard IRAF
+compiler \fIxc\fR, as we shall see in \(sc3.3. See the manual page for
+\fIxc\fR for additional information.
+
+.NH 2
+Host Level Linking to the IMFORT Libraries
+.PP
+In some cases it may be desirable to use host system facilities to compile
+and link programs which use the IMFORT interface. The procedure for doing
+this is host dependent and is completely up to the user, who no doubt will
+already have a preferred technique worked out. All one needs to know in
+this situation are the names of the libraries to be linked, and the order
+in which they are to be linked. The libraries are as follows, using the
+IRAF filenames for the libraries. All the libraries listed are referenced
+internally by the IMFORT code hence are required.
+
+.TS
+center;
+l l.
+lib$libimfort.a IMFORT itself
+lib$libsys.a Contains certain pure code modules used by IMFORT
+lib$libvops.a The VOPS vector operators library
+hlib$libos.a The IRAF kernel (i/o primitives)
+.TE
+.LP
+The host pathnames of these libraries will probably be evident, given the
+host pathname of the IRAF root directory (\fIlib\fR is a subdirectory of
+the IRAF root directory). If in doubt, the \fIosfn\fR intrinsic function may
+be used while in the CL to print the host pathname of the desired library.
+For example,
+.DS
+\fLcl> = osfn ("lib$libimfort.a")\fR
+.DE
+will cause the CL to print the host pathname of the main IMFORT library.
+
+.NH 2
+Calling Host Programs from the CL
+.PP
+Since Fortran programs which use IMFORT are host programs rather than IRAF
+programs, the CL \fIforeign task\fR interface is used to connect the programs
+to the CL as CL callable tasks. The foreign task interface may also be used
+to provide custom CL task interfaces to other host system utilities, e.g.,
+the debugger or the librarian.
+.PP
+The function of the \fItask\fR statement in the CL is to make a new task
+known to the CL. The CL must know the name of the new task, the name of
+the package to which it is to be added, whether or not the new task has a
+parameter file, the type of task being defined, and the name of the file in
+which the task resides. At present new tasks are always added to the
+"current" package. The possible types of tasks are normal IRAF executable
+tasks, CL script tasks, and foreign tasks. Our interest here is only in the
+forms of the task statement used to declare foreign tasks. There are two
+such forms at present. The simplest is the following:
+.DS
+\fLtask $\fItaskname\fR [, \fL$\fItaskname\fR...]\fL = $foreign\fR
+.DE
+This form is used when the command to be sent to the host system to run
+the task is identical to the name by which the task is known to the CL.
+Note that any number of new tasks may be declared at one time with this
+form of the task statement. The \fL$\fR prefixing each \fItaskname\fR
+tells the CL that the task does not have a parameter file. The \fL$foreign\fR
+tells the CL that the new tasks are foreign tasks and that the host command
+is the same as \fItaskname\fR. For example, most systems have a system
+utility \fImail\fR which is used to read or send electronic mail.
+To declare the \fImail\fR task as an IRAF foreign task, we could enter
+the following declaration, and then just call the \fImail\fR task from
+within the CL like any other IRAF task.
+.DS
+\fLtask $mail = $foreign\fR
+.DE
+The more general form of the foreign task statement is shown below.
+The host command string must be quoted if it contains blanks or any other
+special characters; \fL$\fR is a reserved character and must be escaped
+to be included in the command sent to the host system.
+.DS
+\fLtask $\fItaskname\fL = $\fIhost_command_string\fR
+.DE
+In this form of the task statement, the command to be sent to the host system
+to execute the new IRAF task may be any string. For example, on a VMS host,
+we might want to define the \fImail\fR task so that outgoing messages are
+always composed in the editor. This could be set up by adding the \fL/EDIT\fR
+switch to the command sent to VMS:
+.DS
+\fLtask $mail = $mail/edit\fR
+.DE
+Foreign task statements which reference user-written Fortran programs often
+refer to the program by its filename. For the task to work regardless of the
+current directory, either the full pathname of the executable file must be
+given, or some provision must be made at the host command interpreter level
+to ensure that the task can be found.
+.PP
+When a foreign task is called from the CL, the CL builds up the command string
+to be sent to the host command interpreter by converting each command line
+argument to a string and appending it to \fIhost_command_string\fR preceded
+by a space. This is the principal difference between the foreign task
+interface and the low level OS escape facility: in the case of a foreign task,
+the command line is fully parsed, permitting general expression evaluation,
+i/o redirection, background execution, minimum match abbreviations, and so on.
+.PP
+In most cases this simple method of composing the command to be sent to the
+host system is sufficient. There are occasional cases, however, where it is
+desirable to \fIembed\fR the command line arguments somewhere in the string
+to be sent to the host system. A special \fIargument substitution\fR notation
+is provided for this purpose. In this form of the task statement,
+\fIhost_command_string\fR contains special symbols which are replaced by the
+CL command line arguments to form the final host command string.
+These special symbols are defined in the table below.
+
+.TS
+center;
+c l.
+$0 replaced by \fItaskname\fR
+$1, $2, ..., $9 replaced by the indicated argument string
+$\(** replaced by the entire argument list
+$(N) use host equivalent of filename argument N (1-9 or \(**)
+.TE
+
+.PP
+An example of this form of the task statement is the \fIfc\fR task discussed
+in \(sc3.1. As we noted earlier, \fIfc\fR is merely a front-end to the more
+general IRAF HSI command/link utility \fIxc\fR. In fact, \fIfc\fR is
+implemented as a foreign task defined in the default \fIuser\fR package in
+the \fLLOGIN.CL\fR file. The task declaration used to define \fIfc\fR is
+shown below. The task statement shown is for UNIX; the VMS version is
+identical except that the \fL-O\fR switch must be quoted else DCL will convert
+it to lower case. In general, foreign task statements are necessarily
+machine dependent, since their function is to send a command to the host system.
+.DS
+\fLtask $fc = "$xc -h -O $\(** -limfort -lsys -lvops -los"\fR
+.DE
+The argument substitution facility is particularly useful when the host
+command template consists of several statements to be executed by the
+host command interpreter in sequence each time the CL foreign task is called.
+In this case, a delimiter character of some sort is required to delimit
+the host command interpreter statements. Once again, this is host system
+dependent, since the delimiter character to be used is defined by the syntax
+of the host command interpreter. On UNIX systems the command delimiter
+character is semicolon (`\fB;\fR'). VMS DCL does not allow multiple
+statements to be given on a single command line, but the IRAF interface
+to DCL does, using the exclamation character (`\fB!\fR'), which is the
+comment character in DCL.
+.PP
+The \fL$()\fR form of argument substitution is useful for foreign tasks
+with one or more filename arguments. The indicated argument or arguments
+are taken to be IRAF virtual filenames, and are mapped into their host
+filename equivalents to build up the host command string. For example,
+assume that we have an IMFORT task \fIphead\fR, the function of which is
+to print the header of an image in FITS format on the standard output
+(there really is such a program - look in \fLimfort$tasks/phead.f\fR).
+We might declare the task as follows (assuming that \fIphead\fR means
+something to the host system):
+.DS
+\fLtask $phead = "$phead $(*)"\fR
+.DE
+We could then call the new task from within the CL to list the header
+of, for example, the standard test image \fLdev$pix\fR, and page the output:
+.DS
+\fLcl> phead dev$pix | page\fR
+.DE
+Or we could direct the output to the line printer:
+.DS
+\fLcl> phead dev$pix | lpr\fR
+.DE
+Filename translation is available for all forms of argument substitution
+symbols, e.g., \fL$(1)\fR, \fL$(2)\fR, \fL$(\(**)\fR, and so on; merely
+add the parenthesis.
+.PP
+It is suggested that new foreign task statements, if not typed in
+interactively, be added to the \fIuser\fR package in your \fLLOGIN.CL\fR file,
+so that the definitions are not discarded when you log out of the CL or exit
+a package. If you want to make the new tasks available to other IRAF users
+they can be added to the \fIlocal\fR package by adding the task statements
+to the file \fLlocal$tasks/local.cl\fR. If this becomes unwieldy the
+next step is to define a new package and add it to the system; this is not
+difficult to do, but it is beyond the scope of this manual to explain how
+to do so.
+
+.NH 3
+Example 1 Revisited
+.PP
+Now that we are familiar with the details of the foreign task statement,
+it might be useful to review the examples of foreign task statements given
+in \(sc2.1, which introduced the \fIplanck\fR task. The UNIX example given
+was as follows:
+.DS
+\fLcl> task $planck = $planck.e\fR
+.DE
+This is fine, but only provided the \fIplanck\fR task is called from the
+directory containing the executable. To enable the executable to be called
+from any directory we can use a UNIX pathname instead, e.g.,
+.DS
+\fLcl> task $planck = $/usr/jones/iraf/tasks/planck.e\fR
+.DE
+Alternatively, one could place all such tasks in a certain directory, and
+either define the pathname of the directory as a shell environment variable
+to be referenced in the task statement, or include the task's directory in
+the shell search path. There are many other possibilities, of course, but
+it would be inappropriate to enumerate them here.
+.LP
+The VMS example given earlier was the following:
+.DS
+\fLcl> task $planck = "$planck:==\\\\$\fIdisk\fP:[\fIdir\fP...]planck.exe!planck"\fR
+.DE
+The command string at the right actually consists of two separate DCL commands
+separated by the VMS/IRAF DCL command delimiter `\fB!\fR'. If we invent a
+pathname for the executable, we can write down the the first command:
+.DS
+\fL$ planck :== $usr\\\\$2:[jones.iraf.tasks]planck.exe\fR
+.DE
+This is a DCL command which defines the new DCL foreign task \fIplanck\fR.
+We could shorten the CL foreign task statement by moving the DCL declaration
+to our DCL \fLLOGIN.COM\fR file; this has the additional benefit of allowing
+the task to be called directly from DCL, but is not as self-contained.
+If this were done the CL task statement could be shortened to the following.
+.DS
+\fLcl> task $planck = $foreign\fR
+.DE
+The same thing could be accomplished in Berkeley UNIX by defining a cshell
+\fIalias\fR for the task in the user's \fL.cshrc\fR file.
+
+.NH 2
+Debugging IMFORT Programs
+.PP
+Programs written and called from within the IRAF environment can be debugged
+using the host system debug facility without any inconvenience. The details
+of how to use the debugger are highly dependent upon the host system since
+the debugger is a host facility, but a few examples should help the reader
+understand what is involved.
+.PP
+Berkeley UNIX provides two debug tools, the assembly language debugger
+\fIadb\fR and the source language debugger \fIdbx\fR. Both are implemented
+as UNIX tasks and are called from within the IRAF environment as tasks,
+with the name of the program to be debugged as a command line argument
+(this example assumes that \fIadb\fR is a defined foreign task):
+.DS
+\fLcl> adb planck.e\fR
+.DE
+The program is then run with a debugger command, passing any command line
+arguments to the program as part of the debugger run-program command.
+Programs do not have to be compiled in any special way to be debugged
+with \fIadb\fR; programs should be compiled with \fIfc -x\fR to be debugged
+with \fIdbx\fR.
+.PP
+In VMS, the debugger is not a separate task but rather a shareable image
+which is linked directly into the program to be debugged. To debug a program,
+the program must first be linked with \fIfc -x\fR. The program is then run
+by simply calling it in the usual way from the CL, with any arguments given
+on the command line. When the program runs it comes up initially in the
+debugger, and a debugger command (\fIgo\fR) is required to execute the user
+program. Note that if the program is run directly with \fLrun/debug\fR
+there is no provision for passing an argument list to the task.
+
+.NH 2
+Calling IMFORT from Languages other than Fortran
+.PP
+Although our discussion and examples have concentrated exclusively on the
+use of the IMFORT library in host Fortran programs, the library is in fact
+language independent, i.e., it uses only low level, language independent
+system facilities and can therefore be called from any language available
+on the host system. The method by which Fortran subroutines and functions
+are called from another language, e.g., C or assembler, is highly machine
+dependent and it would be inappropriate for us to go into the details here.
+Note that \fIfc\fR may be used to compile and link C or assembler programs
+as well as Fortran programs.
+
+.NH 2
+Avoiding Library Name Collisions
+.PP
+Any program which uses IMFORT is being linked against the main IRAF system
+libraries, which together contain some thousands of external procedure names.
+Only a few hundred of these are likely to be linked into a host program,
+but there is always the chance that a user program module will have the
+same external name as one of the modules in the IRAF libraries.
+If such a library collision should occur, at best one would get an error
+message from the linker, and at worst one would end up with a program
+which fails mysteriously at run time.
+.PP
+At present there is no utility which can search a user program for externals
+and cross check these against the list of externals in the IRAF system
+libraries. A database of external names is however available in the file
+\fLlib$names\fR; this contains a sorted list of all the Fortran callable
+external names defined by procedures in the \fIimfort\fR, \fIex\fR, \fIsys\fR,
+\fIvops\fR, and \fIos\fR libraries (the \fIex\fR library is however not
+searched when linking IMFORT programs).
+.PP
+The \fImatch\fR task may be used to check individual user external names
+against the name list, or a host utility may be used for the same purpose.
+For example, to determine if the module \fIsubnam\fR is present in any
+of the IRAF system libraries:
+.DS
+\fLcl> match subnam lib$names\fR
+.DE
+The names database is also useful for finding the names of all the procedures
+sharing a particular package prefix. For example,
+.DS
+\fLcl> match "^cl" lib$names | table\fR
+.DE
+will find all the procedures whose names begin with the prefix "cl" and
+print them as a table (the \fIlists\fR package must be loaded first).
+
+.bp
+.NH
+The IMFORT Library
+.PP
+In this section we survey the procedures provided by the IMFORT interface,
+grouped according to the function they perform. There are currently four main
+groups: the command line access procedures, the image access procedures,
+the vector operators (VOPS), and a small binary file i/o package. With the
+exception of the VOPS procedures, all of the IMFORT routines were written
+especially for IMFORT and are not called in standard IRAF programs.
+The VOPS procedures are standard IRAF procedures, but are included in the
+IMFORT interface because they are coded at a sufficiently low level that they
+can be linked into any program, and they tend to be useful in image processing
+applications such as IMFORT is designed for.
+.PP
+The ANSI Fortran-77 standard requires that all names in Fortran programs have
+six or fewer characters. To eliminate guesswork, the names of all the IMFORT
+procedures are exactly six characters long and the names adhere to a
+\fBnaming convention\fR. The first one or two characters in each name
+identify the package or group to which the procedure belongs, e.g.,
+\fIcl\fR for the command line access package, \fIim\fR for the image
+access package, and so on. The package prefix is followed by the function name,
+and lastly a datatype code identifying the datatype upon which the procedure
+operates, in cases where multiple versions of the procedure are available for
+a range of datatypes.
+.DS
+\fIpackage_prefix // function_code // type_suffix\fR
+.DE
+The type suffix codes have already been introduced in the examples. They are
+the same as are used throughout IRAF. The full set is \fB[bcsilrdx]\fR, as
+illustrated in the following table (not all are used in the IMFORT procedures).
+
+.TS
+center box;
+cb s s s
+ci | ci | ci | ci
+c | l | c | l.
+Standard IRAF Datatypes
+_
+suffix name code typical fortran equivalent
+=
+b bool 1 \fLLOGICAL\fR
+c char 2 \fLINTEGER\(**2\fR (non-ANSI)
+s short 3 \fLINTEGER\(**2\fR (non-ANSI)
+i int 4 \fLINTEGER\fR
+l long 5 \fLINTEGER\(**4\fR (non-ANSI)
+r real 6 \fLREAL\fR
+d double 7 \fLDOUBLE PRECISION\fR
+x complex 8 \fLCOMPLEX\fR
+.TE
+.PP
+The actual mapping of IRAF datatypes into host system datatypes is machine
+dependent, i.e., \fIshort\fR may not map into INTEGER\(**2 on all machines.
+This should not matter since the datatype in which data is physically stored
+internally is hidden from user programs by the IMFORT interface.
+.PP
+In cases where multiple versions of a procedure are available for operands
+of different datatypes, a special nomenclature is used to refer to the class
+as a whole. For example,
+.DS
+\fLclarg[cird] (argno, [cird]val, ier)\fR
+.DE
+denotes the set of four procedures \fIclargc, clargi, clargr\fR, and
+\fIclargd\fR. The datatype of the output operand (\fIcval, ival\fR, etc.)
+must match the type specified by the procedure name.
+.PP
+With the exception of the low level binary file i/o procedures (BFIO),
+all IMFORT procedures are implemented as subroutines rather than functions,
+for reasons of consistency and to avoid problems with mistyping of undeclared
+functions by the Fortran compiler.
+
+.NH 2
+Command Line Access
+.PP
+The command line access procedures are used to decode the arguments present
+on the command line when the IMFORT program was invoked. This works both
+when the program is called from the IRAF CL, and when the program is called
+from the host system command interpreter. The command line access procedures
+are summarized in Figure 4, below.
+
+.TS
+center;
+n.
+\fLclnarg (\&nargs)\fR
+\fLclrawc (\&outstr, ier)\fR
+\fLclarg[cird] (\&argno, [cird]val, ier)\fR
+.TE
+.sp
+.ce
+Figure 4. Command Line Access Procedures
+
+.PP
+The \fIclnarg\fR procedure returns the number of command line arguments;
+zero is returned if an error occurs or if there were no command line arguments.
+The \fIclargc\fR, \fIclargi\fR, etc., procedures are used to fetch and decode
+the individual arguments; \fIclargc\fR returns a character string, \fIclargi\fR
+returns an integer, and so on. A nonzero \fIier\fR status indicates either
+that the command line did not contain the indexed argument, or that the
+argument could not be decoded in the manner specified. Character string
+arguments must be quoted on the command line if they contain any blanks or
+tabs, otherwise quoting is not necessary. The rarely used \fIclrawc\fR
+procedure returns the entire raw command line as a string.
+
+.NH 2
+Image Access
+.PP
+The image access procedures form the bulk of the IMFORT interface. There are
+three main categories of image access procedures, namely, the general image
+management procedures (open, close, create, get size, etc.), the header access
+procedures (used to get and put the values of header keywords), and the pixel
+i/o procedures, used to read and write image data.
+.PP
+IMFORT currently supports images of up to three dimensions,
+of type short-integer or real.
+There is no builtin limit on the size of an image, although
+the size of image a particular program can deal with is normally limited by
+the size of a statically allocated buffer in the user program. IMFORT does
+not map IRAF virtual filenames, hence host dependent names must be used when
+running a program which uses IMFORT.
+.PP
+IMFORT currently supports only the OIF image format, and images must be
+of type short-integer or real. Since normal IRAF programs support images of
+up to seven disk datatypes with a dimensionality of up to seven, as well as
+completely different image formats than that expected by IMFORT (e.g., STF),
+if you are not careful IRAF can create images which IMFORT programs cannot
+read (don't omit the error checking!). In normal use, however,
+types short-integer and real are by far the most common and images with
+more than two dimensions are rare, so these are not expected to be serious
+limitations.
+
+.NH 3
+General Image Access Procedures
+.PP
+The general image access and management procedures are listed in Figure 5.
+An image must be opened with \fIimopen\fR or \fIimopnc\fR before header access
+or pixel i/o can occur. The image open procedures return an
+\fIimage descriptor\fR (an integer magic number) which uniquely identifies
+the image in all subsequent accesses until the image is closed.
+When the operation is completed, an image must be closed with \fIimclos\fR to
+flush any buffered output, update the image header, and free any resources
+associated with the image descriptor. The maximum number of images which
+can be open at any one time is limited by the maximum number of open file
+descriptors permitted by the host operating system.
+.PP
+New images are created with \fIimopnc\fR and \fIimcrea\fR. The \fIimopnc\fR
+procedure creates a new copy of an existing image, copying the header of
+the old image to the new image but not the data. The new copy image must
+be the same size and datatype as the old image. For complete control over
+the attributes of a new image the \fIimcrea\fR procedure must be used.
+The \fIimopnc\fR operation is equivalent to an \fIimopen\fR followed by an
+\fIimgsiz\fR to determine the size and datatype of the old image, followed by
+an \fIimcrea\fR to create the new image, followed by an \fIimhcpy\fR to copy
+the header of the old image to the new image and then two \fIimclos\fR calls
+to close both images.
+.PP
+Note that \fIimgsiz always returns seven elements in the output array axlen\fR,
+regardless of the actual dimensionality of the image; this is so that current
+programs will continue to work in the future if IMFORT is extended to support
+images of dimensionality higher than three. Images may be deleted with
+\fIimdele\fR, or renamed with \fIimrnam\fR; the latter may also be used to
+move an image to a different directory. The \fIimflsh\fR procedure is used
+to flush any buffered output pixel data to an image opened for writing.
+
+.TS
+center;
+n.
+\fLimopen (\&image, acmode, im, ier) \fRacmode: 1=RO,3=RW
+\fLimopnc (\&nimage, oim, nim, ier) \fRacmode: always RW
+\fLimclos (\&im, ier)\fR
+
+\fLimcrea (\&image, axlen, naxis, dtype, ier)\fR
+\fLimdele (\&image, ier)\fR
+\fLimrnam (\&oldnam, newnam, ier)\fR
+
+\fLimflsh (\&im, ier)\fR
+\fLimgsiz (\&im, axlen, naxis, dtype, ier)\fR
+\fLimhcpy (\&oim, nim, ier)\fR
+\fLimpixf (\&im, pixfd, pixfil, pixoff, szline, ier)\fR
+.TE
+.sp
+.ce
+Figure 5. General Image Access Procedures
+
+.PP
+The \fIimpixf\fR procedure may be used to obtain the physical attributes
+of the pixel file, i.e., the pixel file name, the one-indexed \fIchar\fR
+offset to the first pixel, and the physical line length of an image as stored
+in the pixel file (the image lines may be aligned on device block boundaries).
+These parameters may be used to bypass the IMFORT pixel i/o procedures to
+directly access the pixels if desired (aside from the blocking of lines to
+fill device blocks, the pixels are stored as in a Fortran array).
+The BFIO file descriptor of the open pixel file is also returned, allowing
+direct access to the pixel file via BFIO if desired. If lower level (e.g.,
+host system) i/o facilities are to be used, \fIbfclos\fR or \fIimclos\fR
+should be called to close the pixel file before reopening it with the foreign
+i/o system.
+.PP
+Direct access to the pixel file is not recommended since it makes a program
+dependent upon the details of how the pixels are stored on disk; such a
+program may not work with future versions of the IMFORT interface, nor with
+implementations of the IMFORT interface for different (non-OIF) physical image
+storage formats. Direct access may be warranted when performing a minimum
+modification hack of an old program to make it work in the IRAF environment,
+or in applications with unusually demanding performance requirements,
+where the (usually negligible) overhead of the BFIO buffer is unacceptable.
+Note that in many applications, the reduction in disk accesses provided by
+the large BFIO buffer outweighs the additional cpu cycles required for memory
+to memory copies into and out of the buffer.
+
+.NH 3
+Image Header Keyword Access
+.PP
+The image header contains a small number of standard fields plus an arbitrary
+number of user or application defined fields. Each image has its own header
+and IMFORT does not in itself make any association between the header parameters
+of different images. The header access procedures are summarized in Figure 6.
+Note that the \fIimgsiz\fR procedure described in the previous section is the
+most convenient way to obtain the size and datatype of an open image, although
+the same thing can be achieved by a series of calls to obtain the values of
+the individual keywords, using the procedures described in this section.
+
+.TS
+center;
+n.
+\fLimacck (\&im, keyw, ier)\fR
+\fLimaddk (\&im, keyw, dtype, comm, ier)\fR
+\fLimdelk (\&im, keyw, ier)\fR
+\fLimtypk (\&im, keyw, dtype, comm, ier)\fR
+
+\fLimakw[bcdir] (\&im, keyw, [bcdir]val, comm, ier)\fR
+\fLimgkw[bcdir] (\&im, keyw, [bcdir]val, ier)\fR
+\fLimpkw[bcdir] (\&im, keyw, [bcdir]val, ier)\fR
+
+\fLimokwl (\&im, patstr, sortit, kwl, ier)\fR
+\fLimgnkw (\&kwl, outstr, ier)\fR
+\fLimckwl (\&kwl, ier)\fR
+.TE
+.sp
+.ce
+Figure 6. Image Header Access Procedures
+
+.PP
+Both the standard and user defined header parameters may be accessed via the
+procedures introduced in this section. The \fIimacck\fR procedure tests for
+the existence of the named keyword, returning a zero \fIier\fR if the keyword
+exists. New keywords may be added to the image header with \fIimaddk\fR,
+and old keywords may be deleted with \fIimdelk\fR. The datatype of a keyword
+may be determined with \fIimtypk\fR. The attributes of a keyword are its
+name, datatype, value, and an optional comment string describing the
+significance of the parameter. The comment string is normally invisible
+except when the header is listed, but may be set when a new keyword is added
+to the header, or fetched with \fIimtypk\fR.
+.PP
+The most commonly used procedures are likely to be the \fIimgkw\fR and
+\fIimpkw\fR families of procedures, used to get and put the values of named
+keywords; these procedures require that the keyword already be present in
+the header. The \fIimakw\fR procedures should be used instead of the
+\fIimpkw\fR procedures if it is desired that a keyword be automatically added
+to the header if not found, before setting the new value. Automatic datatype
+conversion is performed if the requested datatype does not match the actual
+datatype of the keyword.
+.PP
+The \fIkeyword list\fR package is the only way to obtain information from
+the header without knowing in advance the names of the header keywords.
+The \fIimokwl\fR procedure opens a keyword list consisting of all header
+keywords matching the given pattern, returning a \fIlist descriptor\fR to
+be used as input to the other procedures in the package. Successive
+keyword \fInames\fR are returned in calls to \fIimgnkw\fR; a nonzero
+\fIier\fR is returned when the end of the list is reached. The keyword
+name is typically used as input to other procedures such as \fIimtypk\fR
+or one of the \fIimgkw\fR procedures to obtain further information about
+the keyword. A keyword list should be closed with \fIimckwl\fR when it is
+no longer needed to free system resources associated with the list descriptor.
+
+.TS
+center box;
+cb s s
+ci | ci | ci
+l | c | l.
+Standard Image Header User Keywords
+_
+name datatype description
+=
+naxis int number of axes (dimensionality)
+naxis[1:3] int length of each axis, pixels
+pixtype int pixel datatype
+datamin real minimum pixel value
+datamax real maximum pixel value
+ctime int image creation time
+mtime int image modification time
+limtime int time min/max last updated
+title string image title string (for plots etc.)
+.TE
+
+.PP
+The keyword list pattern string follows the usual IRAF conventions; some
+useful patterns are "\(**", which matches the entire header, and "i_", which
+matches only the standard header keywords (the standard header keywords are
+really named "i_naxis", "i_pixtype", etc., although the "i_" may be omitted
+in most cases). A pattern which does not include any pattern matching
+metacharacters is taken to be a prefix string, matching all keywords whose
+names start with the pattern string.
+.PP
+An image must be opened with read-write access for header updates to have
+any effect. An attempt to update a header without write permission will
+not produce an error status return until \fIimclos\fR is called to update
+the header on disk (and close the image).
+
+.NH 3
+Image Pixel Access
+.PP
+The IMFORT image pixel i/o procedures are used to get and put entire image
+lines to N-dimensional images, or to get and put N-dimensional subrasters
+to N-dimensional images. In all cases the caller supplies a buffer into
+which the pixels are to be put, or from which the pixels are to be taken.
+The pixel i/o procedures are summarized in Figure 7.
+.PP
+As shown in the figure, there are four main classes of pixel i/o procedures,
+the get-line, put-line, get-section, and put-section procedures. The get-line
+and put-line procedures are special cases of the get/put section procedures,
+provided for programming convenience in the usual line by line sequential
+image operator (they are also slightly more efficient than the subraster
+procedures for line by line i/o). It is illegal to reference out of bounds
+and \fIi1\fR must be less than or equal to \fIi2\fR (IMFORT will not flip
+lines); the remaining subscripts may be swapped if desired. Access may be
+completely random if desired, but sequential access (in storage order) implies
+fewer buffer faults and is more efficient.
+
+.KS
+.TS
+center;
+n.
+\fLim[gp]l1[rs] (\&im, buf, ier)\fR
+\fLim[gp]l2[rs] (\&im, buf, lineno, ier)\fR
+\fLim[gp]l3[rs] (\&im, buf, lineno, bandno, ier)\fR
+\fLim[gp]s1[rs] (\&im, buf, i1, i2, ier)\fR
+\fLim[gp]s2[rs] (\&im, buf, i1, i2, j1, j2, ier)\fR
+\fLim[gp]s3[rs] (\&im, buf, i1, i2, j1, j2, k1, k2, ier)\fR
+.TE
+.sp
+.ce
+Figure 7. Image Pixel I/O Procedures
+.KE
+
+.PP
+Type short and type real versions of each i/o procedure are provided.
+The type real procedures may be used to access images of either type short
+or type real, with automatic datatype conversion being provided if the disk
+and program datatypes do not match. The type short-integer i/o procedures
+may only be used with type short images.
+.PP
+The user who is familiar with the type of image i/o interface which maps
+the pixel array into virtual memory may wonder why IMFORT uses the more old
+fashioned buffered technique. There are two major reasons why this approach
+was chosen. Firstly, the virtual memory mapping technique, in common use on
+VMS systems, is \fInot portable\fR. On a host which does not support the
+mapping of file segments into paged memory, the entire image must be copied
+into paged memory when the image is opened, then copied again when the image
+operation takes place, then copied once again from memory to disk when the
+image is closed. Needless to say this is very inefficient, particularly for
+large images, and some of our applications deal with images 2048 or even 6000
+pixels square.
+.PP
+Even on a machine that supports mapping of file segments into memory, mapped
+access will probably not be efficient for sequential access to large images,
+since it causes the system to page heavily; data pages which will never be
+used again fill up the system page caches, displacing text pages that must
+then be paged back in. This happens on even the best systems, and on a system
+that does not implement virtual memory efficiently, performance may suffer
+greatly.
+.PP
+A less obvious reason is that mapping the image directly into memory violates
+the principle of \fIdata independence\fR, i.e., a program which uses this
+type of interface has a builtin dependence on the particular physical image
+storage format in use when the program was developed. This rules out even
+such simple interface features as automatic datatype conversion, and prevents
+the expansion of the interface in the future, e.g., to provide such attractive
+features as an image section capability (as in the real IRAF image interface),
+network access to images stored on a remote node, support for pixel storage
+schemes other than line storage mode (e.g., isotropic mappings or sparse image
+storage), and so on.
+.PP
+The majority of image operations are either sequential whole-image operations
+or operations upon subrasters, and are just as easily programmed with a
+buffered interface as with a memory mapped interface. The very serious
+drawbacks of the memory mapped interface dictate that it not be used except
+in special applications that must randomly access individual pixels in an
+image too large to be read in as a subraster.
+
+.NH 2
+Error Handling
+.PP
+The IMFORT error handling mechanism is extremely simple. All procedures in
+which an error condition can occur return a nonzero \fIier\fR error code
+if an error occurs. The value of \fIier\fR identifies which of many possible
+errors actually occurred. These error codes may be converted into error
+message strings with the following procedure:
+.DS
+\fLimemsg (\&ier, errmsg)\fR
+.DE
+It is suggested that every main program contain an error handling section at
+the end of the program which calls \fIimemsg\fR and halts program execution
+with an informative error message, as in the examples in \(sc2.
+This is especially helpful when debugging new programs.
+
+.NH 2
+Vector Operators
+.PP
+The vector operators (VOPS) package is a subroutine library implementing
+a large number of primitive operations upon one dimensional vectors of any
+datatype. Some of the operations implemented by the VOPS routines are
+non-trivial to implement, in which case the justification for a library
+subroutine is clear. Even in the simplest cases, however, the use of a
+VOPS procedure is advantageous because it provides scope for optimizing
+all programs which use the VOPS operator, without having to modify the
+calling programs. For example, if the host machine has vector hardware
+or special machine instructions (e.g., the block move and bitfield instructions
+of the VAX), the VOPS operator can be optimized in a machine dependent way
+to take advantage of the special capabilities of the hardware, without
+compromising the portability of the applications software using the procedure.
+.PP
+The VOPS procedures adhere to the naming convention described in \(sc4.
+The package prefix is \fIa\fR, the function code is always three characters,
+and the remaining one or two characters define the datatype or types upon
+which the procedure operates. For example, \fIaaddr\fR performs a vector
+add upon type real operands. If the character \fIk\fR is added to the
+three character function name, one of the operands will be a scalar.
+For example, \fIaaddkr\fR adds a scalar to a vector, with both the scalar
+and the vector being of type real.
+.PP
+Most vector operators operate upon operands of a single datatype: one notable
+exception is the \fIacht\fR (change datatype) operator, used to convert a
+vector from one datatype to another. For example, \fIachtbi\fR will unpack
+each byte in a byte array into an integer in the output array, providing a
+capability that cannot be implemented in portable Fortran. Any datatype
+suffix characters may be substituted for the \fIbi\fR, to convert a vector
+from any datatype to any other datatype.
+.PP
+In general, there are are three main classes of vector operators, the
+\fIunary\fR operators, the \fIbinary\fR operators, and the \fIprojection\fR
+operators. The unary operators perform some operation upon a single input
+vector, producing an output vector as the result. The binary operators
+perform some operation upon two input vectors, producing an output vector
+as the result. The projection operators compute some function of a single
+input vector, producing a scalar function value (rather than a vector) as
+the result. Unary operators typically have three arguments, binary
+operators four, and projection operators two arguments and one output
+function value. For example, \fIaabsi\fR is the unary absolute value
+vector operator, type integer (here, \fIa\fR is the input vector, \fIb\fR
+is the output vector, and \fInpix\fR is the number of vector elements):
+.DS
+\fLaabsi (a, b, npix)\fR
+.DE
+A typical example of a binary operator is the vector add operator, \fIaaddr\fR.
+Here, \fIa\fR and \fIb\fR are the input vectors, and \fIc\fR is the output
+vector:
+.DS
+\fLaaddr (a, b, c, npix)\fR
+.DE
+In all cases except where the output vector contains fewer elements than one
+of the input vectors, the output vector may be the same as one of the input
+vectors. A full range of datatypes are provided for each vector operator,
+except that there are no boolean vector operators (integer is used instead),
+and \fIchar\fR and \fIcomplex\fR are only partially implemented, since they
+are not sensible datatypes for many vector operations. In any case, the VOPS
+\fIchar\fR is the SPP char and should be avoided in Fortran programs.
+.PP
+Once these rules are understood, the calling sequence of a particular VOPS
+operator can usually be predicted with little effort. The more complex
+operators, of course, may have special arguments, and some study is typically
+required to determine their exact function and how they are used. A list of
+the VOPS operators currently provided is given below (the datatype suffix
+characters must be added to the names shown to form the full procedure names).
+
+.TS
+center;
+n.
+aabs -\& Absolute value of a vector
+aadd -\& Add two vectors
+aaddk -\& Add a vector and a scalar
+aand -\& Bitwise boolean AND of two vectors
+aandk -\& Bitwise boolean AND of a vector and a scalar
+aavg -\& Compute the mean and standard deviation of a vector
+abav -\& Block average a vector
+abeq -\& Vector equals vector
+abeqk -\& Vector equals scalar
+abge -\& Vector greater than or equal to vector
+abgek -\& Vector greater than or equal to scalar
+abgt -\& Vector greater than vector
+abgtk -\& Vector greater than scalar
+able -\& Vector less than or equal to vector
+ablek -\& Vector less than or equal to scalar
+ablt -\& Vector less than vector
+abltk -\& Vector less than scalar
+abne -\& Vector not equal to vector
+abnek -\& Vector not equal to scalar
+abor -\& Bitwise boolean OR of two vectors
+abork -\& Bitwise boolean OR of a vector and a scalar
+absu -\& Block sum a vector
+acht -\& Change datatype of a vector
+acjgx -\& Complex conjugate of a complex vector
+aclr -\& Clear (zero) a vector
+acnv -\& Convolve two vectors
+acnvr -\& Convolve a vector with a real kernel
+adiv -\& Divide two vectors
+adivk -\& Divide a vector by a scalar
+adot -\& Dot product of two vectors
+advz -\& Vector divide with divide by zero detection
+aexp -\& Vector to a real vector exponent
+aexpk -\& Vector to a real scalar exponent
+afftr -\& Forward real discrete fourier transform
+afftx -\& Forward complex discrete fourier transform
+aglt -\& General piecewise linear transformation
+ahgm -\& Accumulate the histogram of a series of vectors
+ahiv -\& Compute the high (maximum) value of a vector
+aiftr -\& Inverse real discrete fourier transform
+aiftx -\& Inverse complex discrete fourier transform
+aimg -\& Imaginary part of a complex vector
+alim -\& Compute the limits (minimum and maximum values) of a vector
+alln -\& Natural logarithm of a vector
+alog -\& Logarithm of a vector
+alov -\& Compute the low (minimum) value of a vector
+altr -\& Linear transformation of a vector
+alui -\& Vector lookup and interpolate (linear)
+alut -\& Vector transform via lookup table
+amag -\& Magnitude of two vectors (sqrt of sum of squares)
+amap -\& Linear mapping of a vector with clipping
+amax -\& Vector maximum of two vectors
+amaxk -\& Vector maximum of a vector and a scalar
+amed -\& Median value of a vector
+amed3 -\& Vector median of three vectors
+amed4 -\& Vector median of four vectors
+amed5 -\& Vector median of five vectors
+amgs -\& Magnitude squared of two vectors (sum of squares)
+amin -\& Vector minimum of two vectors
+amink -\& Vector minimum of a vector and a scalar
+amod -\& Modulus of two vectors
+amodk -\& Modulus of a vector and a scalar
+amov -\& Move (copy or shift) a vector
+amovk -\& Move a scalar into a vector
+amul -\& Multiply two vectors
+amulk -\& Multiply a vector and a scalar
+aneg -\& Negate a vector (change the sign of each pixel)
+anot -\& Bitwise boolean NOT of a vector
+apkx -\& Pack a complex vector given the real and imaginary parts
+apol -\& Polynomial evaluation
+apow -\& Vector to an integer vector power
+apowk -\& Vector to an integer scalar power
+arav -\& Mean and standard deviation of a vector with pixel rejection
+arcp -\& Reciprocal of a scalar and a vector
+arcz -\& Reciprocal with detection of divide by zero
+arlt -\& Vector replace pixel if less than scalar
+argt -\& Vector replace pixel if greater than scalar
+asel -\& Vector select from two vectors based on boolean flag vector
+asok -\& Selection of the Kth smallest element of a vector
+asqr -\& Square root of a vector
+asrt -\& Sort a vector in order of increasing pixel value
+assq -\& Sum of squares of a vector
+asub -\& Subtract two vectors
+asubk -\& Subtract a scalar from a vector
+asum -\& Sum of a vector
+aupx -\& Unpack the real and imaginary parts of a complex vector
+awsu -\& Weighted sum of two vectors
+awvg -\& Mean and standard deviation of a windowed vector
+axor -\& Bitwise boolean XOR (exclusive or) of two vectors
+axork -\& Bitwise boolean XOR (exclusive or) of a vector and a scalar
+.TE
+
+.PP
+A non-trivial example of the use of vector operators is the case of bilinear
+interpolation on a two dimensional image. The value of each pixel in the
+output image is a linear sum of the values of four pixels in the input image.
+The obvious solution is to set up a do-loop over the pixels in each line of
+the output image, computing the linear sum over four pixels from the input
+image for each pixel in the output line; this is repeated for each line in the
+output image.
+.PP
+The solution using the VOPS operators involves the \fIalui\fR (vector look up
+and interpolate) and \fIawsu\fR (weighted sum) vector operators. A lookup table
+defining the X-coordinate in the input image of each pixel in a line of the
+output image is first generated. Then, for each line of the output image,
+the two lines from the input image which will contribute to the output image
+line are extracted. \fIAlui\fR is used to interpolate each line in X, then
+\fIawsu\fR is used to form the weighted sum to interpolate in the Y direction.
+This technique is especially efficient when bilinear interpolation is being
+used to expand the image, in which case the \fIalui\fR interpolated X-vectors,
+for example, are computed once but then used to generate several lines of
+the output image by taking the weighted sum, a simple and fast operation.
+When moving sequentially up through the image, the high X-vector becomes the
+low X-vector for the next pair of input lines, hence only a single call to
+\fIalui\fR is required to set up the next region.
+.PP
+The point of this example is that many or most image operations can be
+expressed in terms of primitive one dimensional vector operations,
+regardless of the dimensionality of the image being operated upon.
+The resultant algorithm will often run more efficiently even on a conventional
+scalar machine than the equivalent nonvectorized code, and will probably run
+efficiently without modification on a vector machine.
+.PP
+Detailed specification sheets (manual pages) are not currently available for
+the VOPS procedures. A summary of the calling sequences is given in the file
+\fLvops$vops.syn\fR, which can be paged or printed by that name while in the
+CL, assuming that the system has not been stripped and that the sources are
+still on line. The lack of documentation is really not a problem for these
+operators, since they are all fairly simple, and it is easy to page the source
+file (in the \fIvops\fR directory) to determine the exact calling sequence.
+For example, to examine the source for \fIawsu\fR, type
+.DS
+\fLcl> page vops$awsu.gx\fR
+.DE
+to page the generic source, regardless of the specific datatype of interest.
+If you have trouble deciphering the generic source,
+use \fLxc -f file.x\fR to produce the Fortran translation
+of one of the type specific files in the subdirectories
+\fLvops$ak\fR and \fLvops$lz\fR.
+
+.NH 2
+Binary File I/O (BFIO)
+.PP
+The IMFORT binary file i/o package (BFIO) is a small package, written
+originally as an internal package for use by the IMFORT image i/o routines
+for accessing header and pixel files (the VOS FIO package could not be used
+in IMFORT without linking the entire IRAF/VOS runtime system into the Fortran
+program). Despite its original conception as an internal package, the package
+provides a useful capability and is portable, hence has been included in the
+IMFORT interface definition. Nonetheless, the user should be warned that BFIO
+is a fairly low level interface and some care is required to use it safely.
+If other suitable facilities are available it may be better to use those,
+although few interfaces will be found which are simpler or more efficient
+than BFIO for randomly accessing pre-existing or preallocated binary files.
+.PP
+The principal capability provided by BFIO is the ability to randomly access
+a binary file, reading or writing an arbitrary number of char-units of storage
+at any (one-indexed) char offset in the file. The file itself is a non-record
+structured file containing no embedded record manager information,
+hence is suitable for access by any program, including non-Fortran programs,
+and for export to other machines (this is usually not the case with a Fortran
+unformatted direct access file). Unlike the mainline IMFORT procedures,
+many of the BFIO procedures are integer functions returning a positive count
+value if the operation is successful (e.g., the number of char units of storage
+read or written), or a negative value if an error occurs. Zero is returned
+for a read at end of file.
+
+.TS
+center;
+n.
+\fLbfaloc (\&fname, nchars, status)\fR
+\fLfd = bfopen (\&fname, acmode, advice) \fRacmode: 1=RO,3=RW,5=NF
+\fLbfclos (\&fd, status) \fRadvice: 1=random,2=seq
+
+\fLnchars = bfread (\&fd, buf, nchars, offset)\fR
+\fLnchars = bfwrit (\&fd, buf, nchars, offset)\fR
+
+\fLnchars = bfbsiz (\&fd)\fR
+\fLnchars = bffsiz (\&fd)\fR
+\fLchan = bfchan (\&fd)\fR
+\fLstat = bfflsh (\&fd)\fR
+.TE
+.sp
+.ce
+Figure 8. Low Level Binary File I/O Procedures
+
+.PP
+BFIO binary files may be preallocated with \fIbfaloc\fR, or created with
+\fIbfopen\fR and then initialized by writing at the end of file.
+Preallocating a file is useful when the file size is known in advance, e.g.,
+when creating the pixel file for a new image. The contents of a file
+allocated with \fIbfaloc\fR are uninitialized. To extend a file by writing
+at the end of file the file size must be known; the file size may be obtained
+by calling \fIbffsiz\fR on the open file.
+.PP
+Before i/o to a file can occur, the file must be opened with \fIbfopen\fR.
+The \fIbfopen\fR procedure returns as its function value an integer
+\fIfile descriptor\fR which is used to refer to the file in all subsequent
+accesses until the file is closed with \fIbfclos\fR. Binary data is read
+from the file with \fIbfread\fR, and written to the file with \fIbfwrit\fR.
+Any amount of data may be read or written in a single call to \fIbfread\fR
+or \fIbfwrit\fR. All user level i/o is synchronous and data is buffered
+internally by BFIO to minimize disk transfers and provide for the blocking
+and deblocking of data into device blocks. Any buffered output data may be
+flushed to disk with \fIbfflsh\fR. The function \fIbfchan\fR returns the
+descriptor of the raw i/o channel as required by the IRAF binary file driver.
+.PP
+BFIO manages an internal buffer, necessary for efficient sequential i/o and
+to hide the device block size from the user program. Larger buffers are
+desirable for sequential i/o on large files; smaller buffers are best for
+small files or for randomly accessing large files. The buffer size may be
+set at \fIbfopen\fR time with the \fIadvice\fR parameter. An \fIadvice\fR
+value of 1 implies random access and causes a small buffer to be allocated;
+a value of 2 implies sequential access and causes a large buffer to be
+allocated. Any other value is taken to be the actual buffer size in chars,
+but care must be used since the value specified must be some multiple of the
+device block size, and less than the maximum transfer size permitted by the
+kernel file driver. Note that when writing at end of file, the full contents
+of the internal buffer will be written, even if the entire buffer contents
+were not written into in a \fIbfwrit\fR call. The buffer size in chars is
+returned by \fIbfbsiz\fR.
+.PP
+Since BFIO is a low level interface, the file offset must always be specified
+when reading from or writing to the file, even when the file is being accessed
+sequentially. Contrary to what one might think, file offsets are one-indexed
+in the Fortran tradition, and are specified in units of \fIchars\fR.
+Do not confuse \fIchar\fR with the Fortran \fLCHARACTER\fR; \fIchar\fR is the
+fundamental unit of storage in IRAF, the smallest datum which can be accessed
+as an integer quantity with the host Fortran compiler, normally
+\fLINTEGER\(**2\fR (16 bits or two bytes on all current IRAF hosts).
+
+.bp
+.SH
+Appendix: Manual Pages for the Imfort Procedures
+.PP
+This section presents the ``manual pages'' for the IMFORT and BFIO procedures.
+The manual pages present the exact technical specifications of each procedure,
+i.e., the procedure name and arguments (not necessarily obvious in the case of
+a typed family of procedures), the datatypes and dimensions of the arguments,
+and a precise description of the operation of the procedure.
+Each procedure is presented on a separate page for ease of reference.
+.PP
+The following conventions have been devised to organize the information
+presented in this section:
+.RS
+.IP \(bu
+The manual pages are presented in alphabetical order indexed by the procedure
+name.
+.IP \(bu
+A single manual page is used to present an entire family of procedures which
+differ only in the datatype of their primary operand. The name on the manual
+page is the generic name of the family, e.g., \fIclargi\fR, \fIclargr\fR, etc.,
+are described in the manual page \fIclarg\fR.
+.IP \(bu
+In some cases it makes sense to describe several related procedures with a
+single manual page. An example is the keyword-list package, consisting of
+the procedures \fIimokwl\fR, \fIimgnkw\fR, and \fIimckwl\fR. In such a case,
+since the procedures have different names the manual page for the group is
+duplicated for each procedure in the group, so that the user will not have
+to guess which name the manual page is filed under.
+.IP \(bu
+The \fIsynopsis\fR section of each manual page defines the calling sequence of
+each procedure, the datatypes and dimensions of the arguments, and notes
+whether each argument is an input argument (\fL#I\fR) or an output argument
+(\fL#O\fR).
+.IP \(bu
+The \fIreturn value\fR section describes the conditions required for
+successful execution of the procedure, normally indicated by a zero status
+in \fIier\fR. A symbolic list of the possible error codes is also given.
+The numeric values of these error codes are defined in \fLimfort$imfort.h\fR
+and in \fLlib$syserr.h\fR, but the exact numeric codes should be used only for
+debugging purposes or passed on to the \fIimemsg\fR procedure to get the error
+message string. The numeric error codes are likely to change in future versions
+of the interface hence their values should not be "wired into" programs.
+.RE
+.PP
+Manual pages for the VOPS procedures are not included since VOPS is not really
+part of the IMFORT interface, and it is not yet clear if the VOPS procedures
+are complex enough to justify the production of individual manual pages.