Go to the previous, next section.

Calling SM from Programmes

The SM callable interface is different from that of Mongo and corresponds directly to the interactive version. Almost all of the commands available in SM can be called from either fortran or C, the exceptions being those concerned with the macro processor, variables, history, and vector manipulations. We assume that if you want to call graphics routines directly, then you are prepared to take responsibility for such things. In C (and probably pascal, modula, or ADA), the calls have the same names as the commands, so to set the limits say limits(0.0,1.0,0.0,1.0);. On VMS, and with some unix systems (notably HPUX and AIX), if you are writing fortran, you must prepend an `f' to the command - call flimits(0.0,1.0,0.0,1.0). If you forget this `f', your programmes will compile, but they `won't' work. (They'll give segmentation violations, most likely. Why? Because you will be calling the C functions directly, not the Fortran interface functions, and the languages have different ways of passing arguments, so e.g. you will pass the address of the variable from your Fortran program to a C function that expects to get the value of the variable. This translation is precisely what the interface functions are set up to do for you). @footnote #{Under Unix the loader can often distinguish fortran from C, so you may not need the `f' -- call limits(0.0,1.0,0.0,1.0)}

This situation is further complicated by the fact that, to avoid naming conflicts with operating system library functions, SM is often built with the prefix `sm_' prepended to the function name, so e.g. when you issue the box command, the subroutine that is called is named sm_box. Then, if you use callable SM, from C the function name is sm_box, but from Fortran on VMS and other systems, the function you must call is fsm_box. (The functions are renamed by the SM guru by defining the macro RENAME in `options.h' when compiling SM. And in fact, exactly how the name is changed is up to the guru. `sm_' is merely the common, and default, choice).

So how are you supposed to know what to call the functions? Well, our best suggestion is to ask the person who build SM on your system (unless you are that person, in which case, N.B. the SM distribution does define RENAME by default). The second best suggestion is to look in `libplotsub.a' (or `libplotsub.olb' on VMS systems), and see what the names of the functions are. On VMS, try this:

lib/list/names libplotsub/lib
and look at the names it lists under module INTERFACE. On a unix system you can use strings. But it is a bit messier, so you should filter the output e.g. as follows
strings libplotsub.a | grep errorbar
If you see things in the output like sm_errorbar, then you know that the functions were renamed. If you see things like fsm_errorbar, then you know this is one of those machines where you have to prepend the `f' for the fortran interface functions.

If you used an ANSI compiler to link SM (or your guru did) then you will need to provide prototypes for the SM functions that you call if you use the C interface (Fortran knows nothing of such things). This can be done by including the file `sm_declare.h'. You need the prototypes as some SM functions expect float (not double) arguments.

In what follows, we will assume that you are not writing fortran under VMS, so we will omit the leading effs.

To use SM functions, you must link with appropriate libraries. You will always need to link with the three SM libraries, libplotsub, libdevices, and libutils in that order. Specifically, under Unix, you'll need to include the files `libplotsub.a', `libdevices.a', and `libutils.a' when you link (it's probably easier to use -lplotsub -ldevices -lutils, along with a -Ldir if needed). and under VMS you'll need `libplotsub.olb/lib', `libdevices.olb/lib', and `libutils.olb/lib'. I can't tell you where they'll be on your system. In addition, you may need to link (after utils) any libraries used by the devices that have been compiled into your version of SM. For example, if you use the X-windows driver, you'll need to link with the X-library (-lX). Consult a local guru in case of any trouble - the person who installed SM has had to work this out already.

A list of functions giving the calling sequence for all the available functions follows, but first an example. Note especially the use of graphics and alpha to set the terminal to graphics mode, and return to a normal terminal afterwards. We would recommend always calling these, if they do nothing (e.g. on a laser printer) they'll do no harm. A related function is gflush() which will update graphics on the screen, for instance with stdgraph where output is usually buffered.

Some devices (such as GL on an SGI, or X-windows on machines without backing store such as RS/6000's) need some help from you to redraw the screen. You do this by calling redraw whenever you are waiting for input, passing it `0' (the file descriptor of standard input, for those of you familiar with C). When input is ready, redraw will return and your application can proceed. It should do no harm on systems where it does no good.

There are examples of programmes (both C and fortran) calling SM in the directory sm/callable; you might want to look at them before starting your own project.

        integer NXY
        parameter (NXY=20)
        integer sm_device
        integer i
        real x(NXY),y(NXY)
c
        do 1 i=1,NXY
           x(i) = i
           y(i) = i*i
1  continue
c
        if(sm_device('hirez') .lt. 0) then
            print *,'Can"t open hirez'
            stop
        endif
        call sm_graphics
        call sm_defvar("TeX_strings","1")
        call sm_limits(-1.,22.,0.,500.)
        call sm_ctype('red')
        call sm_box(1,2,0,0)
        call sm_ptype(40.,1)
        call sm_points(x,y,NXY)
        call sm_xlabel('X axis')
        call sm_ylabel('Not x axis')
        call sm_alpha
        print *,'hit any key to exit'
        call sm_redraw(0)
        read(5,*) i
        end
Remember, if you were running VMS, HPUX, or AIX then all those calls would start `f' - call fsm_graphics and so forth. Note that box takes all of its four possible arguments, and that commands such as points add an argument to specify the number of points to plot. You must, of course, ensure that you use the correct type of variables, passing integers or reals as required (and as listed below). If you are using C, you must carefully distinguish between passing by value, and passing by address (which we only use when an array is expected, and for returning a cursor position).

The functions are as follows. For fuller definitions of the arguments look at the main description of the command. The only ones that are different are conn for connect (due to a collision with a system routine), and curs, defvar, and plotsym because they don't quite correspond to any interactive commands. A common source of trouble is not noticing that the ptype call is the vector form of the command, so to set a ptype of `4 1' you must say ptype(41.0,1).

The arguments are declared in fortran in this list. real x(n) means that x is an array of size n. `Real' means single precision. (So in C, character char *; integer int; real float; real() float *. We deal with converting the calling conventions from one language to another, but note comments at the bottom of this table.)

alpha
Set terminal back to a normal state
angle(a)
Set angle to a (real a)
axis(a1,a2,as,ab,ax,ay,al,il,ic)
Draw an axis. (real a1,a2,as,ab; integer ax,ay,al,il,ic)
box(x1,y1,x2,y2)
Draw a box - note 4 args. (integer x1,y2,x2,y2)
conn(x,y,n)
Connect a line. (real x(n),y(n); integer n)
ctype(c)
Set colour to c (character c)
curs(x,y,k)
Return position of cursor (real x,y; integer k)
defvar(str1,str2)
Select variable str1 to str2 (character str1, str2)
device(str)
Select device str (character str); return integer
dot
Draw a dot
draw(x,y)
Draw to (x,y) in user coords (real x,y)
erase
Erase screen
errorbar(x,y,e,k,n)
Draw error bars (real x(n),y(n),e(n); integer k,n)
expand(e)
Set expand to e (real e)
format(xf,yf)
Set format strings to xf and yf (character xf,yf)
gflush
Flush graphics output
graphics
Set terminal into plotting mode
grelocate(x,y)
Relocate in screen coordinates (integer x,y)
grid(i)
Draw a grid (integer i)
hardcopy
Close current device, if appropriate make hardcopy
histogram(x,y,n)
Draw a histogram (real x(n),y(n); integer n)
identification(str)
Identification string (character str)
label(str)
Draw a string (character str)
limits(x1,x2,y1,y2)
Set limits (real x1,x2,y1,y2)
location(x1,x2,y1,y2)
Set location (integer x1,x2,y1,y2)
ltype(lt)
Set ltype (integer lt)
lweight(lw)
Set lweight (integer lw)
notation(xl,xh,yl,yh)
Set axis format defaults (real xl,xh,yl,yh)
plotsym(x,y,n,sym,ns)
Draw user points (real x(n),y(n); integer n,sym(3*ns),ns)
points(x,y,n)
Draw points (real x(n),y(n); integer n)
ptype(pp,n)
Set point type - vector form (real pp(n); integer n)
putlabel(i,str)
Position a label (integer i; character str)
redraw(i)
Wait for input on file descriptor i (integer i).
relocate(x,y)
Relocate in user coords (real x,y)
shade(delta,x,y,n,type)
Shade a region (integer delta; real x(n),y(n); integer n,type)
ticksize(xs,xb,ys,yb)
Set ticksize (real xs,xb,ys,yb)
window(nx,ny,x,y)
Select a window (integer nx,ny,x,y)
toscreen(ux,uy,sx,sy)
Convert to screen coordinates (real ux,uy, integer sx,sy)
xlabel(str)
Draw x-axis label (character str)
ylabel(str)
Draw y-axis label (character str)

Device returns 0 if it opens the requested device, or -1 if it fails. You must declare device as returning integer, of course. Curs returns after you hit any key, returning the coordinates of the point, and the key struck as an integer (e.g. `a' as 97 in ascii). In C, all three arguments are pointers, two to float and one to int. Defvar defines a variable, it is identical to the interactive command DEFINE name value. It is only used to define variables that are significant to SM, currently file_type and TeX_strings. Fortran users might or might not need to double \s in TeX labels, depending on the foibles of your compilers (you are more likely to need the doubled \\ under unix). Plotsym is like first using the PTYPE { ... 2 command to define sym, and then POINTS to plot x against y. The ns array consists of triples of integers, (move x y) where move is 1 to move the plot pointer, 0 otherwise. This is not quite the same as the interactive command, but doesn't involve any characters. The move integer may not be omitted. The `file descriptor' that redraw demands will almost always be 0 (standard input) on unix boxes; if it is needed by VMS or other operating systems I will add a note here when I write the device driver. Shade shades the inside of the curve specified by x and y if type is 1, or the area below a histogram specified by x and y if type is 2. The line spacing in screen coordinates is delta. You can use toscreen to convert from user to screen coordinates (which run from 0 to 32767, and are used by grelocate). The second pair of arguments should be pointers to int if called from C.

The use of the 2-D functions may require a little more explanation. If you want to use SM to read your data, producing contour plots is very similar to doing so interactively, with the difference that instead of defining the variable file_type, you must call the function filetype with the desired value as the argument before reading the data. This is equivalent to calling defvar to define the variable file_type, and is only supported for backwards compatibility. As an alternative, you can fill your own data array, and pass it to SM to be contoured with defimage. The function calls follow (again in fortran), followed by some explanation.

contour
Contour current 2-D image
defimage(arr,x1,x2,y1,y2,nx,ny)
Define an image (real arr(nx,ny),x1,x2,y1,y2; integer nx,ny)
delimage
delete current 2-D image
filetype(type)
Set 2-D filetype (character type)
levels(l,n)
Set levels for contour (real l(n); integer n)
minmax(x,y)
Get minimum and maximum of image (real x,y)
readimage(file,x1,x2,y1,y2)
Read a 2-D image (character file; real x1,x2,y1,y2)
The translation to other languages is not quite as simple as above. In C, minmax expects to be passed pointers to floats, and the first argument to defimage is not a 2-D array, but an array of pointers to the rows of the image. x1, x2, y1, y2 specify the limits as in the interactive IMAGE command; if they are set to be 0.0 then the dimensions of the array will be used. As an example, again in non-VMS fortran:
        integer NXY
        parameter (NXY=20)
        integer sm_device
        integer i,j
        real z(NXY,NXY),lev(NXY)
c
        do 2 i=1,NXY
           do 1 i=1,NXY
              x(i,j) = (i-NXY/2)**2 + (j-1)**2
1          continue
2       continue
c
        if(sm_device('postscript latypus') .ne. 0) then
           print *,'Can"t open printer'
           stop
        endif
        call sm_graphics
        call sm_limits(-1.,21.,-1.,21.)
        call sm_box(1,2,0,0)
        call sm_defimage(z,0.,20.,0.,20.,NXY,NXY)
        call sm_minmax(amin,amax)
        do i=1,NXY
           lev(i)=amin + (i - 1.)/(NXY - 1)*(amax - amin)
3       continue
        call sm_levels(lev,NXY)
        call sm_contour
        call sm_hardcopy
        call sm_alpha
        end
It is also possible to call the SM parser directly from your own programmes. This is usually done by people who have large data arrays that they want to plot, so we have also provided a call to define your arrays as SM vectors. To use this, your SM guru must build an extra library, (called `libparser.a' on unix systems). This is done with the command
        make Parser
in the top level SM source directory. If this has been done, you can link the parser into your code by including the flag -lparser before the other SM libraries (but after any -L flags). The programmes `interp' and `finterp' in the `callable' directory provide examples of calling SM's parser; `finterp.f' looks like:
      real a(10)
      integer i

      do 1 i=1,10
         a(i) = i
 1    continue

      call sm_array_to_vector(a,10,'xyz')
      print *,'Calling SM parser...'
      call sm_parser('-q')
      print *,'Exited parser'
      end
Here the array a (with 10 elements) is to be called xyz in SM, and SM is to be invoked with the command line options -q. You can of course define as many vectors as you feel like, but using DELETE to delete them from the parser is a serious error (i.e. don't!).

array_to_vector(arr,n,name)
Define an SM vector called name to have the values of the array arr. (real arr(n); int n; character name).

parser(args)
Start up the SM command parser as if you had started SM interactively with command line arguments args, but with some vectors predefined (those that you defined using array_to_vector) (character args).

Go to the previous, next section.