SM Manual

Edition 2.4.16 (or later if we didn't update this page)


by Robert Lupton and Patricia Monger

Introduction


SM is still evolving slowly, and this documentation may not be
true, helpful, or complete. In order of increasing plausibility,
information may be obtained from the HELP command, this document, the
authors, and the source code. RHL is prepared to guarantee that the
executable code has not been patched.



If you find bugs, (reasonable) features that you want, wrong documentation,
or anything else that inspires you please let us know. At least under
Unix the macro gripe should be a convenient way to send us mail.
Please also send us any clever macros that you would like to share.



Next a disclaimer: SM is copyright (C)1987, 1989, 1990, 1991,
1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000
Robert Lupton and Patricia Monger.
This programme is not public domain, except where specifically stated
to the contrary, either in the code, or in the manual. If you have a
legally acquired copy you may use it on any computer "on the same site",
but you may not give it away or sell it. If you have a legal copy we
will provide some support and allow you with as many upgrades
as you provide tapes for (or wish to retrieve with ftp).


SM is provided `as is' with no warranty, and we are not responsible for any
losses resulting from its use.



In addition to this manual there is a tutorial introduction which you
might find less intimidating.
See section `The SM Tutorial' in The SM Tutorial.



This should be unimportant, but in case it isn't you can submit SM
bug reports (or requests for new features) using the URL
http://www.astro.princeton.edu/cgi-bin/gnatsweb.pl;
you want to query on category sm (and maybe smdoc) from

advanced query; note that you can save this query, set a bookmark,
and so forth.

Description of SM


SM is an interactive plotting programme with a flexible
command language. The plot data may be defined to SM in a number of ways.
There is also a powerful mechanism for defining and editing plot `macros'
(sets of SM plot commands that are defined and
invoked as plot "subprogrammes").


The
features of SM are described fully in the next few sections, but
let us start with a description of how to produce your first SM
plot. Before you start, notice that SM is case sensitive.
Keywords may be typed in lower or uppercase (as we do in this manual),
but we would recommend using lowercase. It is in fact possible to change
the meanings of lowercase keywords, but this can be confusing. If you are
interested, see the section on "overloading".
See `uppercase' in the index
if you really want to use your shift key.

A simple plot





Let us assume that you have a file called mydata, which looks
like this:

This is an example file

1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512


SM has a history mechanism, so
first type DELETE 0 10000 to tell SM to forget any
commands that it has remembered. Then choose a device to plot on. You
do this with a command like dev tek4010. If you don't know what
to call your terminal, use the LIST DEVICE command, ask some local
expert, look at the description
of DEVICE, or (if desperate) read the manual (see section The Stdgraph Graphics Kernel).
You'll know that
you have succeeded if typing BOX draws a box.



You should now have successfully chosen a graphics terminal. To actually
plot something, use the following set of commands. The text after the
# is a comment, you don't have to type this (or the #).

DATA mydata             # Specify desired datafile
LINES 3 100             # Choose which lines to use
READ i 1                # Read column 1 into `i'
READ { ii 2 iii 3 }     # Read column 2 into `ii' and 3 into `iii'
LIMITS i ii             # Choose limits, based on i and ii
BOX                     # Draw the axes
PTYPE 4 0               # Choose square point markers
POINTS i ii             # Plot i against ii
CONNECT i ii            # and connect the points
XLABEL This is i        # Label the X-axis
YLABEL This is ii       # And the Y



You should now have a graph. If you had wanted to plot the third
column instead of the second
you could have typed LIMITS i iii POINTS i iii instead.
And of course you could plot ii against iii as a third
alternative. You
were not limited to only use squares as markers or solid lines to
connect them - see PTYPE and LTYPE for details.


If you want a logarithmic plot, SM makes that easy for you.
You can take logs of a vector using the LG (or LN) commands
on vectors; try it - SET x=1,10 SET y=x**3 set ly=LG(y) LIMITS x ly
CON x ly box
. You might have wanted the axes to reflect the fact that you
had logged the y axis. The TICKSIZE command allows you to do this, and
this is in fact the commonest use of it. Try TICKSIZE 0 0 -1 0, and
then repeating the x-y plot.


What if you want hard copy of your hard-earned graph? There is a
command (actually a macro) called playback which will repeat all
the commands that you have typed. Type ERASE to clear the screen, then
HISTORY to see the commands that you have issued. You probably
don't want the ERASE command to be repeated, so type DELETE

to delete it(1).



If there are any other mistakes use DELETE m n to delete
the lines m to n containing them.
Now type playback and your plot should reappear. But we wanted a
hardcopy, so type dev laser lqueue (or whatever your friendly Guru
recommends as a hardcopy device), then playback. This time, those
plotting commands will appear on the laser printer not your terminal. To
make them actually appear, type hardcopy or issue another

dev command.
Be sure to say dev tek4010 (or whatever device you chose)
before you read any more of this
document. It is possible to edit the playback buffer, rather than
simply deleting lines from within it. The section on `examples'
describes how to do this.



In fact, the same plot could have been produced from a data file which
just contained the first column. After saying READ i 1, you could
have said SET ii = i*i SET iii = i**3 and proceeded from there, or
even skipped the file altogether by saying set i = 1,8 instead of

READing it at all. Such possibilities, and a good deal more, are
described in greater detail in the rest of this manual.



What we just did was to define a simple `macro', in this case the
special one called all which playback manipulates. A more
explicit use of a macro would be to define a macro to square a vector,
that is to square each element of a vector.
To do this say(2)

MACRO square 2 { SET $1 = $2*$2 } 


So to calculate the vector ii we could now say

square ii i


which is the same as saying

SET ii = i*i 

So now that you have met macros, how do you save them? The simplest
and least reliable way is to use SM's history, and hope that
the next time that you use SM it remembers the MACRO
command that you used to define square, so you can re-issue it.
(Try exiting SM, then starting it up again and typing
HISTORY, then ^nnn where nnn is the number
which is next to the desired command in the resulting list.)


A brute force way is to say SAVE filename which will save almost
all of your SM environment, to be recovered using the
RESTORE filename command at some later time, or later SM
session.
Specifically, SAVE will save all your macros, variables, and
vectors, along with your history buffer. This is a very convenient
way in practice but it does mean that you tend to carry around
lots of long-forgotten
macros, variables, and vectors.



Another way is to write the macros to a disk file, using the
MACRO WRITE command (see `Macros'). Then you can retrieve
your macros with MACRO READ. You should note that your macro

all will simply be a macro - to put it onto the history list
say DELETE 0 10000 WRITE HISTORY all. (Of course, you could
write a macro to do this for you).
Maybe saving your
playback buffer is something better done with SAVE, which will
restore your playback buffer, while
preparing files of useful macros is a use for MACRO READ.
Once the idea of macros gets into your blood, you can of course use
an editor to create your own files of macros, to be read with
MACRO READ.

Facilities within the Command Interpreter


This is a guide to the use of SM variables, the macro processor,
the help command, and the history facilities.
The vector arithmetic and plotting facilities are described below. Various
examples are scattered throughout the text, to give some guidance on the
use of SM's capabilities.



Perhaps the most important thing to know is how to escape from
SM. If you have a prompt, simply type QUIT(3).
If you are running some command, try control-C to get a prompt.
Most commands will eventually return control to the keyboard following a
control-C. In addition, the parser is reset, and the input buffer cleared.
Sometimes control-C leaves a } on the buffer if it thinks that it'll
help get back to the prompt, which can generate an irrelevant syntax error.
Occasionally it can still be confused -- try typing a few characters
and maybe a }.



When you have interrupted SM with a control-C, a
macro called error_handler is executed, if it is defined. The one
that we provide does things like setting the expansion back to 1, and
resetting any window commands that you might have issued, and then
prints a message handler... to tell you that it's done its work.
If you don't like this,
see `private initialisation' in the index for how to get your own
handler loaded automatically.



If you make a mistake, and SM notices a syntax error, it'll
print a message indicating where you were and which macro you were
running. It is possible for the wrong macro to be reported (if
SM has finished reading the macro before detecting the error),
in which case you'll be told that the error occurred in a macro that
called the offender. Setting VERBOSE (see section Verbose)
to 3 or 4 provides a
more direct way of finding the true location of the error.



If you define the variable traceback to be 1 (maybe with the line
traceback 1 in your `.sm' file)




you'll get a traceback of what macros were active when the error occurred;
the same caveats about the wrong macro being reported apply.
In addition, the usual interrupt capabilities of your operating system will
work under SM, with a couple of quirks.



Under Unix, in case of emergency, type control-\, and SM
will ask you if you want to return to the prompt, and if you
don't it'll offer a core dump, and then exit. As
usual, typing control-Z (from the C-shell) will interrupt the process, which may
be restarted later.
Under VMS, control-Z will interrupt SM, and return you to the command
interpreter (DCL). Typing CONTINUE will then allow you to restart
SM(4).




If SM is running in a SPAWNed sub-process, then control-Z will
reATTACH you to its parent. To continue SM, use the DCL ATTACH
command.
We strongly suggest that you learn how to do this, it makes life much
easier -- all you have to do is SPAWN a process from DCL and start SM
from there. Do check with your VMS system manager to ensure that you have the
right quotas for SPAWNing (Process limit must be at least 3, because SM
will use one for itself and one for hardcopies). An especially simple
way to do all this is is to use the command file `kept_SM.com' in the
main SM directory. It'll handle the spawning and attaching for you.



Another fact to bear in mind is that the characters ^, $, and

# are special, as ^ is used by the history system,






$ introduces a
variable, and # starts a comment. The special meanings of all of
these characters
except ^ can be turned off by preceding them with a \. To type a ^,
use the quote_next character
(initially control-Q or ESC-q) to quote the ^; i.e. type

ESC-q.(5)
A \n is interpreted as a carriage return, and a \ as the
last character on a line escapes the newline, so that the line and the one
following it are treated as one long line.
A \ preceding any other character
(except a "; see next paragraph) is simply a \. This character
is used to set font types in the LABEL commands, so it has no
special meaning to the command interpreter, which simplifies the entering of
strings for LABEL commands.




A further problem is that symbols such as +, -, *,
and / are used
to separate words, which is what you want for mathematics, but maybe not what
you had in mind for filenames.



Enclosing a word
in double quotes turns off all special meanings except ^; an embedded
" may be escaped with a \.
Single quotes are used quite differently; enclosing a word in 'single quotes'
makes it into a string so '12' is a two-character string and not
an integer at all. There are times when this is important; for example
if(y == 'yes') tests if the vector y is equal to the
string `yes', whereas if('yes' == 'yes') asks whether two
identical strings are equal (they are). When you remember that I can
legally say set yes='no' you'll appreciate the distinction.




The characters {} also perform quoting, turning off the special
meanings of all characters (including single and double quotes, but not
^). The difference between double quotes and braces is that
the latter have grammatical value; they are part of the syntax that
SM understands. In most cases you can use angle brackets instead of
curly ones if the grammar needs the brackets but you don't want to
turn off expansions (see section String Variables).


SM is case-sensitive. It will
accept keywords in either upper or lower case, but this is a special
dispensation on its part. If you insist on typing in uppercase say
load uppercase when you first start SM, or put the line
uppercase 1 in your `.sm' file.

Furthermore keywords may not be abbreviated.
This is not a great hardship as it is easy to define macros which
make the minimum abbreviation a synonym for the full command. Many such
macros are predefined for you when you first use SM; see section The System Macro Libraries
for details. In particular, certain common
abbreviations of commands have been predefined by the
SM startup file.




Every time that SM is started, it looks for an environment file
called `.sm' which consists of names of variables and their
values. From # to the end of a line is taken to be a comment. A list
of directories to be searched in order for `.sm' files
is compiled into SM, it usually
consists of the current directory, then your home directory, and then
some system directory. The system default can be over-ridden by
defining the environment variable SMPATH which is
a list of directories separated by single spaces. Each directory on the
search path is tried in turn until a file is found containing the desired
variable, which allows your choices to take preference over those of the
system administrator. In the list of directories
. is taken to be the current directory, and ~ is
your home directory unless you specified a command line -u name

option, in which case it is taken to be name's home directory instead. This
means that sm -u name will usually run SM as if you were name.
If name is null, then SM won't look for a `.sm' file in
anyones home directory.


The default path is equivalent to an SMPATH of

export SMPATH=". ~ /u/sm/lib/"


(or an equivalent incantation). Note
that the directory /u/sm/lib/ ends in a / so that a filename
can be directly appended (on a VMS system it would probably end in a :

or ]).



An example file would be (the filenames are written in Unix)

# I'm a comment line
fonts       /users/sm/fonts.bin
graphcap    /users/sm/graphcap
help        /users/sm/help/
macro       /users/sm/macros/

name        Robert         # Or alternatively `Dr._Lupton'




The fonts file contains the SM fonts (in a binary form),



the graphcap entry is used to
define the file used to describe graphics terminals (see section The Stdgraph Graphics Kernel),


help is the directory used by the help command,


macro is the default directory where macros reside,


and name is what SM will call you (you can put spaces
into your name by using underscores, e.g. My_Lord will be
referred to as My Lord).
You can access
entries in the environment file yourself, as described
in the section on variables. See the section section The System Macro Libraries
to see how entries in the `.sm' file are used to influence the
behaviour of SM, or consult your local expert. You might want
to borrow someones `.sm' file when you first use
SM, although you should do fine without one. For more detail, and
further special entries, see section Environment Variables.



The name of the `.sm' file can be specified on the command line as
"-f name" or you can ask to use name's .sm file with
-u name.
VMS users should ensure that SM has been installed
as a foreign command to take advantage of these capabilities.





SM then tries to read in any macros
in the file `default' in the directory `macro'
and attempts to execute the macro startup if it exists.


If -m filename appears on the command line, this is taken to be the
name of another file of macros and these are read, and the eponymous macro
is executed (after any pre- or suf- fix has been removed. For instance if
you start
SM with the command sm -m /home/tst.m, it will first read
the file /home/tst.m, and then attempt to execute the
macro tst).(6)




Anything left on the command line is treated as if it had been typed
at the prompt, for example sm restore vital.save will start
by RESTORing from the file vital.save (see RESTORE
if you want to know what this means). The -m option is not
really a good way to personalise SM. The startup macro
discussed under `useful macros', which is run every time that you start
SM, looks for a directory macro2 in your `.sm'

file, and if it is there reads a file `default' from it, and
executes the macro startup2 which it expects to find there.
On case-insensitive operating systems, such as VMS, you may need to
quote the command line to prevent it being translated to upper case.
SM then

attempts to read a set of history commands from a file in
the current working directory, passes control to the input routine
and issues a prompt.
The file is given by the entry hist_file in your `.sm'
file, and if it isn't present then no history will be remembered.



You are then able to type commands, as many as
will fit on one line(7),
and use the features described below.



You can use a combination of these features to run SM in `batch' mode.
If you had a history file that you just wanted to run, then you could
start SM, say playback, and quit. You could have a macro
called batch in batch.m that did just that, and say
sm -m batch.m to execute it. In fact, you don't even need your own
macro as one is pre-defined for you so sm batch is sufficient.
You could write your own macros along this lines to do more complex tasks.


A more convenient alternative (under unix) would be sm -S < history_file
where the -S is explained in the next paragraph.



For completeness, we should mention the other command line flags,
-h, -l logfile, -n, -q,

-s, -S, -v#, and -V.






The -h prints a summary of command line options,
if you specify a logfile with -l everything that you type at the
keyboard is copied into the logfile (except editing commands). When you
start SM it usually runs a macro startup; -n prevents this.
The -s (for `stupid', or `silent' or `suppress') flag disables the
command line editor (although the history list is still saved, so commands
like playback will work),

-q suppresses the initial `Hello' message,
and -S is like -s but it also suppresses the prompt
and stops SM from intercepting control-c. You can get the same effect
as -s from inside SM with the command TERMTYPE none.
If you are reading from a file or pipe SM behaves as if you had
invoked it with the -S flag.


This is useful if SM is
being run from inside another programme, via a pipe (VMS: mailbox), or
on a very stupid terminal.

If you want to set a particular value of verbose, use -v for example
-v-3 is equivalent to the VERBOSE -3 command given interactively.
If you want to know SM's version string without starting SM, you can use
the -V flag.

String Variables






Some SM users seem to be confused by variables and vectors; if you are one
of these, the section on quoting (see section What Quotes What When) might help.



SM maintains a set of variables which are defined with one of the statements

DEFINE name value


or

DEFINE name { value_list }


or

DEFINE name ( expression )

where name must consist of digits, letters and `_' (but must not start
with a digit), and may be a keyword.



Value may be a word or a number. Value_list has no such
restrictions
and may contain many words. Note that due to the presence of the {},
variables are not expanded (i.e. replaced by their value) in value_list,
whereas they are in value. In fact, the list can be delimited by

<> rather than {}; see DEFINE for details.



The expression in DEFINE variable ( expr ) should be
a scalar; if it is not, the first element of the vector will be used and
you will be warned, if VERBOSE
(see section Verbose) is one or greater.


Sometimes you just want to evaluate an expression and treat the answer
as a string; in this case use the special vector form $(expr)
which is replaced by the value of the expression -- for example
echo e is $(exp(1)).
Expressions are further discussed under `Vectors and Arithmetic'.



There are a number of special variables whose value is always the current
value of some internal SM variable such as the current position or the
point type. The variable "date" is also special and expands to give
the current time and date, -- try typing echo $date. You can freeze
these variables at their current value by saying define name |
(see below).



Each time SM reads $name it replaces it by its
value, considered as a character string. For example,

DEFINE hi hello
WRITE STANDARD $hi


will print hello. This expansion is done before even the lowest level
of lex analysis, so if a command is attempting to read a value
it is possible to give it the name of a SM variable. An example
would be the XLABEL command, which writes a string as the x-axis label
of a graph,

DEFINE name Aelfred
XLABEL My name is $name


will invoke the XLABEL command, and write My name is Aelfred below
the x-axis. (Incidentally, DEFINE Aelfred Aethelstan YLABEL $$name

will write Aethelstan as the y-axis label, which can be handy in macros.
The use of the double $$ indicates to SM to do a double
translation, as it first expands to $Aelfred which then expands to
Aethelstan).




A variable can be deleted by DEFINE name DELETE so for example the macro


MACRO undef 1 { DEFINE $1 DELETE }


invoked as

undef name


will undefine the variable name (see the section on macros if you are
confused).






There are also three special values, :, |, and
?. The command define name : means `get the
value of name from the environment file'. If this fails, and if the
variable is all uppercase, SM will then try to use the value of an
environment (VMS: logical) variable of the same name.
Using define name ? means
`read the value of name from the keyboard'. You can specify a prompt to be
used, see DEFINE for details.
The form with | has changed a little with version 2.1.1. The variables
that you can use with | have not changed, but their usage has
slightly. They are all defined for you when SM starts and each is always
correct, tracking the current value of the corresponding internal variable.
For example, try echo $angle angle 45 echo $angle. If you now
say define angle |, $angle will cease to track the internal
value and will remain fixed (the same effect can be achieved with

define angle 45). When you say define angle delete it will
once more track the internal value. Your old code will continue to work,
but in many cases it is possible to remove the explicit definition
with |. This special sort of variable will not be SAVEd,
and will not show up if you list the currently defined variables.
A list of the | variables is given in the section on DEFINE.



So using the example `.sm' environment file listed in the previous
section of the manual, DEFINE name : will define

name to be Robert, DEFINE angle | will give the last
value set by the ANGLE command, and DEFINE datafile ? will ask you
for the value of `datafile', which can be useful in macros. For example,

DEFINE noise ? { Ring bell? } IF('$noise' != 'n') { bell }


will execute the macro bell if you type anything but n in reply
to the question `Ring bell?'.





When writing macros, it is also sometimes useful to know if a variable
has been defined. The variable $?name has the value 1 if name
is defined, otherwise it is 0. For instance, there is a line

define term : if($?term) { termtype $term } 


in the startup file, to set a termtype if present in the environment
file.




There are also commands to read the values of variables from data
files defined with the DATA command.

DEFINE name READ i


or
DEFINE name READ i j



will set name to be the i'th line of the file (or the j'th word
of the i'th line). An example is given in the section on `useful macros'.
You can read variables from the headers of binary files (specified
with the IMAGE command) using
DEFINE name IMAGE, although this is only supported for a limited
class of file_type's (see section Two-Dimensional Graphics).



All currently defined variables may be listed with

LIST DEFINE [ begin end ]


where the optional begin and end define the range of variables
(alphabetically) to be listed. You might prefer to use the macro lsv

which won't appear on your history list.




Variables are usually not expanded within double quotes or { }. If
for some reason you need to force expansion within double quotes, it can be
done with $!name.

The macro `load' discussed under useful macros gives an
example of this mechanism. If you need to expand a variable, with no questions
asked (and even within {}), use $!!name.




Sometimes you may want to terminate a variable name where SM doesn't
want to, and this can be done with a trick involving
double quotes. Say you are writing a macro to find all the stars redder
than B-V = 1.0 in a set of data vectors, and you want to rename them with
a trailing "_red", so star goes to star_red. So you
write a foreach loop,

FOREACH x ( U B V R I J K ) { SET $x_red = $x IF(B-V >1)}


Well, that won't work because SM thinks that you are referring
to a previously defined variable named x_red, so it will
complain that x_red is not
defined. But if you write it as $x""_red the "" separate
the x from the _red until $x is expanded,
and then disappear, and all is well. When a variable is read, SM
skips over all whitespace before the definition, and this can cause
problems if you hit control-C in the middle, as the rest of the command
will be thrown away. If you ever hit a control-C, and can't get a
prompt, try typing any non-whitespace character.





Variables are string-variables, and are not primarily designed
for doing arithmetic (that's what vectors are for). This is a common source
of confusion so let's consider some examples (at the risk of anticipating
some later sections of the manual).

DEFINE a 12


defines a variable a which consists of the two characters `1' and `2',
and which can be used anywhere -- for example

xlabel $a. What about vectors? Consider

SET x=10


which defines a single-element vector whose value is ten, ready to be used in
expressions such as

SET y=$a + x*12


Note that the $a is still just the two characters `1' and `0',
but in this context that is interpreted as the number ten. So what does

DEFINE y $a+x*12


do? Well, actually it results in a syntax error (the `+' ends a word), so try

DEFINE y <$a+x*12>


This defines the variable y as the string `10+x*12', it doesn't evaluate
the expression. You can evaluate the expression if you want with

DEFINE y ( $a+x*12 )


which defines y as the string `130'. Incidently, you can sometimes get
away without an explicit variable with the syntax $($a+x*12) which
also expands to the string `130'.



The fact that variables are simply strings can be used to build complex
commands; consider for example the macro

readem          # read multiple lines columns with names in row 1
                READ ROW names 1.s
                DEFINE rc <$(names[(0)]) 1>

                DO i=2,DIMEN(names) {
                        DEFINE rc <$rc $(names[($i - 1)]) $i>
                }
                LINES 2 0
                READ < $rc >



which reads the names of a set of columns from line 1, builds a command
to read the data in the variable rc, and then reads all the data
in one command. You could of course loop through names reading
each column in turn, but this should be a good deal faster.



By default variables are global, so if you have a variable $i, and
a macro that you call also uses a variable $i, the macro will change
the value that you so carefully defined. To avoid this, it is possible to
force variables (and also vectors) to be local, using a command like
DEFINE i LOCAL; in this case the variable $i will softly and
suddenly disappear when you leave the current macro (and therefore you
cannot make variables local at the topmost level, i.e. at the command prompt).
In fact, such variables aren't strictly local, they have what's called
nested scope, as they are visible from any macros that you may call -- they
simply do not propagate backwards up the call stack. You are free to make
a variable local in any (or all) macros, there's no restriction on how
deep such local declarations may be nested.

Command History





It is often very useful to be able to repeat a command, or perhaps correct
a mistake in what you have just typed. Ways of doing this are usually
referred to as `history', and SM has two distinct mechanisms.
One is very similar to that of the Unix C-Shell,
and the other allows you to edit commands using a syntax similar to the popular
editor `emacs', or a generalisation of the DCL history under VMS.
If you are not familiar with Unix, emacs, or VMS don't despair; a
description of the commands and how to invoke them follows in this
document.
Both of these mechanisms are implemented by the routine which reads input
lines. As each line is sent to the parser, it is copied onto a
history list. This list may be printed with HISTORY, and
the commands may be


re-used by referring to them by number, as ^nn, or by a unique
abbreviation, as ^abbrev. In addition, the last command may be
repeated by using ^^ and the last word of the last command by

^$.(8)
These symbols are expanded as soon as they are recognised (see examples,
or experiment), and are then available for modification by the editor.
Sometimes a ^string will retrieve a command beginning
string, but not the one that you want. Version 2.1.1 no longer
supports the use of ^TAB
to search for the next-most-recent command beginning string,
but you can use the search commands (control-R and control-S) instead.
Some people really don't want ^ to be their
history character, either because they're used to something else (such
as !), or because they want to type lots of real ^s (e.g. you are using
TeX-style strings); if this describes you, rebind them -- see the next
section.
If you are considering the history list as a sort of programme to be
repeated you may think that HISTORY lists the commands in the
wrong order; if so use HISTORY -.


For example, if I type:

PROMPT @
echo I like SM
HISTORY


SM will set the prompt to be @, replace the macro echo by
its value WRITE STANDARD and print

I like SM


and then

3   HISTORY
2   echo I like SM
1   PROMPT @


(The actual numbers will be different, depending on what other commands
you have executed, and also because SM may have read a history
file. In that case
there'll be many more commands on the list, but no matter.) If I then type

^2 <CR>


(that is ^2 not control-2)
the screen will look like

@ echo I like SM
I like SM


as if I had just typed it in (@ is the prompt) . Typing

^^ (Yes, ^$ ) <CR>


will now result in SM printing (truthfully)

I like SM (Yes, SM )




It is possible to delete commands from the history buffer with the
DELETE command. If the command is given with zero, one, or two
arguments, then
the specified range is deleted (but their numbers are not re-used). If
no arguments are given, the last command on the buffer is deleted, and
its number is released to be re-used. In other words, the command
DELETE will delete first itself, and then the
previous command from the history list. The command DELETE HISTORY

only removes itself from the history list, and
several of the common commands are defined as macros which use it,
for instance dev is defined as
DELETE HISTORY DEVICE. This means that the command will not
appear on the history list, to confuse you when you do a playback. But
if you now innocently use dev in a macro, that macro won't appear
on the list either. Still worse, if you use dev twice in one
macro, the previous command will be deleted as well which could be quite
confusing.


You can also delete lines of history using ESC-control-D as
described shortly.



The numbering is consecutive, starting at zero. Each command retains its
number until you use a HISTORY command to list the remembered
commands, in which case they are all renumbered, and it is these new numbers
that are listed.



By default only 80 lines are remembered,
and as you continue typing earlier
ones fall off the list.



Because the history buffer is also used to compose complex commands, this
limit can be aggravating. You may be able to defeat this by
putting many commands on
each line (you may have to use \n to terminate label
commands explicitly)
or by writing macros. Alternatively you can define a longer history buffer
when you start SM by including an entry history in your
environment file



which gives the number of commands to be remembered. If you set
history to be 0 the history list is made infinitely long.
Incidently, it is
the total
number of commands that matters, not the range of history
numbers present.



This limit on the number of history lines isn't enforced while writing a
macro onto the history list (using WRITE HISTORY). You can
use this fact to write a sneaky macro that extends your history; type
HELP extend_history if you are interested.




Some people seem to like their history editors to remember where they were,
so that after they retrieve and execute a command the next control-P
or
will retrieve the command one further back on the
history list (that is, if you have just retrieved command number 123
and executed it as command number 234, then control-P will get you
command number 124; you can execute it as command number 235). If
this describes you, define the variable remember_history_line,
which you can either do directly, or by putting a line
remember_history_line 1 in your `.sm' file.





The editor allows you to modify commands, either as you type them or
as you retrieve them from the history list. The various editing
commands may be bound to keys of your choosing, but the default
bindings are given in this list of possible commands:


control-A

Go to start of line.
control-B


Go back one character. (Equivalent to
).
control-C

Interrupt (as usual).
control-D

Delete character under cursor.
control-E

Go to end of line.
control-F

Go forward one character. (Equivalent to
).

control-H

Identical to control-? (DEL). Delete character to left of cursor.
control-I (TAB)

Insert spaces up to the next tab stop. By default a tab
is taken to be 8 characters wide, but this may be changed by specifying
tabsize in your `.sm' file.


control-J (LF)

Equivalent to control-M.
control-K

Delete to end of line. The deleted string is stored,
and may be restored using control-Y, repeatedly if so desired.
control-L


Redraw the current line.
control-M (CR)

Send line to be executed. Some terminals seem to replace
control-M with a linefeed (control-J), thereby making it impossible to make
SM obey you. We therefore make control-@ equivalent to control-M for
emergency use. (This is control-space on many terminals).


control-N

Get the next command on the history list, if it exists
(see control-P). (Equivalent to
).
control-O

Execute the previous command on the history list.
Equivalent to control-Pcontrol-Econtrol-M.
control-P


Get the previous command on the history list, if it exists
(see control-N).(Equivalent to
).
control-Q

Quote next character; Turn off any special significance to
the editor. control-Q is often used by the terminal, so we have defined
control-[-q (that is escape followed by q) as an alternative.
control-R

Search backwards (reversed) for a string; the opposite of

control-S. The `string' can actually be any regular expression (see the
manual entry for APROPOS). If you specify a zero-length string
(i.e. simply hit carriage return) the previous search string will be reused.

control-S

Search forward for a string; the opposite of control-R.
control-S is often used by the terminal, so we have defined
control-[-s (that is escape followed by s) as an alternative.
control-T


Toggle insert/overwrite. By default, characters are
inserted before
the cursor. If overwrite is set, they replace the character under the
cursor. Note that ESC-u will not correctly restore words deleted
with ESC-d in overwrite mode.
control-U

Delete from the cursor to the start of the line.
control-V

Go forward 5 lines.

control-W

Delete the previous word. Identical to ESC-h
control-Y


Insert the string most recently deleted with control-K after the cursor.
control-Z

Return to the operating system, without killing
SM. (Under VMS, if you are running SM in a spawned
subprocess control-Z will attach you to DCL. Otherwise, SM returns you
to DCL.)
control-? (DEL)

Equivalent to control-H.

ESC-control-D

Delete this line and remove it from the history list.
Note that this is different from just clearing a line with (e.g.) control-U,
which only erases a copy of the line.
ESC-<

Go to the first line of a macro, or the oldest history command.

ESC->

Go to the last line of a macro, or the most recent history command.
ESC-g

Go to a given line of a macro, or a given history
command. You'll be prompted for the line number, if you change your mind
you can get out with DEL or control-H.
ESC-q

Quote the next character, turning off any special
significance to the editor. Identical to control-Q.
ESC-s


Search forward for a string. Identical to control-S.
ESC-v

The opposite of control-V, go back 5 lines.
ESC-y

Like control-Y, except that it gets older deletions, cycling
back through a collection of (currently 5) deleted lines.


Some ESC-letter combinations are available which operate
upon complete words. A word is defined as a whitespace delimited
string, so 2.998e8 is a perfectly good word. In addition, it is possible
to undelete words that have been deleted with an ESC-d or ESC-h.

ESC-b

Go to the start of the previous word.
ESC-d

Delete to the beginning of the next word.
ESC-f

Go to the beginning of the next word.

ESC-h

Delete back to the beginning of the current word.
The same as control-W.
ESC-u

Restore the last word deleted, putting it before the
cursor. Further ESC-u's will restore more words. When no more are
available, the bell is rung.


Any printing character is inserted before the cursor (unless overwrite
has been set with control-T ). Illegal characters ring the terminal bell.
If you insert a non-printing character on a line, the cursor may get confused.



If ever you are stuck at the command interpreter, and you want to send
a signal to the operating system (e.g. a control-Y to DCL), but
SM is catching the key and using it for its own purposes, the
easiest thing to do is to define a macro such as
MACRO aa {aa} , and then run it. While it is running (i.e.
until you type control-C) keys should have their usual functions.

Changing Key-Bindings




As mentioned above, it is possible to redefine the meanings of keys to
the history (and macro) editor.
The command EDIT keyword key-sequence will make typing that
sequence of keys correspond to the command keyword. For example,
to make control-R redraw the current line, you could say EDIT
refresh control-R
.



The keyword can be any in
the list below, or any single character. Each character in the
key-sequence can be a single character, control-c, or \nnn where
nnn is an octal number.
Alternatively, READ EDIT filename will
read a file specifying the new bindings which has two lines of header,
followed by pairs of keyword key-sequence. Lines starting with a
# are comments. An example is the
file for VMS users given below.


A problem can come up with multiple-key sequences. Imagine that you have
bound some function to control-Xcontrol-A, for example

        EDIT end_of_line ^X^A


then what happens when you try it? SM sees the control-X and uses its
default binding, exit_editor, and then sees a control-A and
goes to the start of the line, which wasn't the desired effect. The solution
is to tell SM that control-X is not a legal key, in which case it will
either ring the terminal bell (if there are no key-sequences starting with
an control-X), or wait for the next key. In short,

        EDIT illegal ^X
        EDIT end_of_line ^X^A


should work.



On a somewhat similar topic, the KEY (see section Key) command may be
used to define a key to generate a string. See the end of the section on
macros for how this works.



All the current key definitions may be listed using LIST EDIT,
including the KEY definitions.

The names of operators, and their
default bindings, are given in the following table:


control-A

start_of_line

control-B

previous_char
control-C

control-D

delete_char
control-E

end_of_line
control-F


next_char
control-G

illegal
control-H, DEL

delete_previous_char
control-I

tab
control-J


carriage_return
control-K

kill_to_end
control-L

refresh
control-M, control-@

carriage_return
control-N


next_line
control-O

insert_line_above
control-P

previous_line
control-Q, ESC-q

quote_next
control-R


search_reverse
control-S

search_forward
control-T

toggle_overwrite
control-U

delete_to_start
control-V

scroll_forward

control-W, ESC-h

delete_previous_word
control-X

exit_editor
control-Y

yank_buffer
control-Z

attach_to_shell

ESC-<

first_line
ESC->

last_line
\034

escape
ESC-b

previous_word

ESC-d

delete_next_word
ESC-f

next_word
ESC-g

goto_line
ESC-u

undelete_word
ESC-v


scroll_back
ESC-y

yank_previous_buffer
ESC-control-D

delete_from_history
^

history_char



A simple example of a bindings file for a hardened VMS user might be

# This is a set of DCL-ish key maps for SM
# name   key
toggle_overwrite        ^A
start_of_line           ^H
delete_previous_word    ^J
yank_buffer             ^R
search_reverse          ^[r
attach_to_shell         ^Y


Note that that's the two characters
^ and A not control-A. It could just as well have been
written \001.
We need a new character for yank_buffer now that control-Y is
otherwise engaged, and I have chosen control-R (which means that I
can't use control-R to search backwards, so I chose ESC-r for

that).
You should be warned that some
terminal protocols map control-M to control-J, so this use of control-J could
render you unable to issue commands. As mentioned above, in an emergency
control-@ can be used instead of control-M.


When SM is started, or whenever the TERMTYPE command is
used to change terminals, the arrow keys are bound to the commands
previous_line, ext_line, previous_char, and
ext_char. For terminals such as a Televideo-912, which uses
characters such as control-K for arrow motion, these can supersede the
previous meanings (in this case kill_to_end);
The only fix is to use the EDIT or

READ EDIT command to get what you want, probably within a macro.



If you want to use ' as your history character instead of ^
you need to say edit history_char ` edit ^ ^. If you try
to use a character special to SM such as ! this won't work
(you'll get a syntax error) and you'll have to use the next alternative,
namely put the commands into a file and say read edit filename,
for example:

# Change the history character
# name   key
history_char   !
^              ^


Because this particular change is so common, it's possible to specify
that ` be your history character simply by including a line
history_char ` in your `.sm' file (or you can choose your
own character. Choosing 0 has the effect of using the default, ^).








SM needs to know something about the terminal that you are
using, so as to run the history/macro editor. This is entirely
separate from the problem of describing the terminal's graphics. It
will try to discover what sort of terminal you're on by using the value
of term from your `.sm' file,

or failing that the value
of the environment variable TERM (Unix) or the logical variable
TERM (VMS). A term entry of selanar -21 is
equivalent to a TERMTYPE selanar -21 command.
You can also use the TERMTYPE command directly.
SM then uses the terminal
type specified to look up its properties in the termcap database
(see section Termcap -- A Terminal Database). You can also use

TERMTYPE to specify the size of the screen, or to turn off
SM's idea of where the cursor is. On some terminals, you can
only send a cursor to an absolute position and this is chosen to be
the bottom of the screen. This is not what you want for, e.g., a VT240
as it will lead to your graph scrolling off the screen. The use of a
negative screen size to TERMTYPE will disable this cursor
motion, but will also make editing lines slower. If a line of your
graph is being deleted when the SM prompt appears, you may
need to use TERMTYPE dumb or TERMTYPE none.


Talking to the Operating System





Any line from ! to the newline is passed to your shell (DCL under VMS,
the Bourne shell under unix. If you set the variable SHELL in
either your `.sm' file or the environment it will be used instead;
the former takes priority).(9)

For example, !ls or !directory will list the current directory.
The return code from the command is available in the variable

$exit_status, on unix systems it will be 0 for success, for weirder
systems you should look in the system manual for the return value of the
C function system. $exit_status is one of the variables
that can be set with DEFINE exit_status |.



It is also possible to change the directory that SM uses to look
for data or macro files with the CHDIR command - for instance

CHDIR "../more_data"(10).
If a directory name starts with `~', CHDIR replaces the `~'
with your home directory. This is the only place that `~' is treated
specially, for instance it is not interpreted by the DATA command.
Because directory names often contain mathematical
characters such as [ or /, it is wise to quote the directory, or
use the macro cd which quotes it for you.


Macros



In SM, it is possible to define sets of plot commands as
"subprogrammes", which can be used just like a plot command, to generate
a standard plot. These plot macros allow variables (e.g.
name of the data file, plot label or limits, etc) to be supplied at
execution time.


You can also bind commands to keys to save typing; for example I
usually bind `cursor' to the PF1 key of my terminal. Such keyboard
macros are discussed under KEY and at the bottom of this section.



The macro facility consists of commands to define macros,
delete them, write them to disk files, read them from disk files,
delete all those macros defined in a specified disk file and




list all currently defined macros. In addition, the help command
applied to a macro prints out its definition.

It is possible to pass up
to 9 arguments to a macro, referred to as $1, ... , $9,
and in addition $0 gives the name of the macro.
While macro arguments are
being read they are treated as if they are in sets of {}, except
that variables are expanded. If you want to include a space in
an argument, enclose it in quotes. If the number of declared arguments is
10 or more, the macro is treated as having a variable number of arguments.
If it is 100 or more the last argument extends to the end of the line.
For further discussion see the discussion of how macros are used.




A macro is defined by the statement

MACRO name nargs { body-of-macro }


or

MACRO name nargs < body-of-macro >


where name may be up to 80 characters, and must not be a
keyword(11),
and body-of-macro is the statements within the macro, and may
be up to 2000 characters long. Macros defined using an editor on a file
may be up to 10000 characters. If nargs, the number of
arguments, is 0 it may
be omitted. Macros may also be created using the MACRO EDIT command,
which is discussed below, and which is probably easier. To define the macro
in a disk file, the file format must be: the name of the macro starts in the
first column, followed by a tab or spaces, followed by the number of
arguments, if greater than 0, followed by commands, followed by
comments if any. The next line and
any necessary subsequent lines
contain the macro definition (starting in a column other than the first
one)
. Any number of macros may appear in the same file, as long as the macro
name is given in the first column and the definition starts in some other
column. The first two blanks or tabs are deleted in continuation
lines, but any further indentation will survive into the macro definition.
Tabs will be replaced by spaces as the macro is read. By default a tab
is taken to be 8 characters wide, but this may be changed by specifying

tabsize in your `.sm' file.




When a macro is invoked, by typing its name wherever a command is
valid, for example at a prompt, it first reads its arguments from the
terminal (if they are not in the lookahead buffer, it will prompt you
for them), and defines them as the variables $1, ..., $9,
before executing the commands contained within the macro. The
number of arguments must be declared correctly.

As an alternative it is possible to declare that a macro has a
variable number of arguments by declaring 10 or more(12).
The macro will
then expect between 0 and the number declared modulo 10 arguments, all
on the same line as the macro itself. (i.e. the argument list is
terminated by a newline, which may either be a `real' one, or an \n).
If the number of arguments is 100 or more it is still reduced modulo 10,
but the last argument is taken to be the rest of the line (which may
consist of many words).


The macro may find out if a particular argument is provided by using
$? to see if the variable is defined. For example the macro check,
in the format in which it would appear in a file,

check  11   if($?1 == 1) { echo Arg 1 is $1 }\n


will echo its argument, if it has one, and

split  102  if($?2 == 0) { DEFINE 2 "(none)" }
echo $1:$2:


if invoked as split word many arguments will print word:many arguments:.
If you add an explicit newline, split word many\n arguments,
you'll get word:many: and then a complaint that arguments

is not a macro.



If you try to execute a non-existent macro, if it is defined SM will
call a special macro called macro_error_handler.
It has two arguments; the first is the string
NOT_FOUND, and the second is the name of your non-existent macro.


When you start SM, the error handler is:

macro_error_handler 2 ## handle errors associated with macros
		if($?missing_macro_continue) {
		   echo $2 is not a macro
		   RETURN
		}
		if('$1' == 'NOT_FOUND') {
		   del1
		   define 3 "$2 is not a macro; aborting"
		} else {
		   define 3 "Unknown macro error for $2: $1"
		}
		USER ABORT $3


which causes an immediate syntax error (the USER ABORT),
and remove the errant command from the history list (the del1). You
can turn this off by defining the variable $missing_macro_continue,
which you can do in your `.sm' file; this was the default in SM versions
2.1.0 and earlier, and is what you get if the macro

macro_error_handler isn't defined.



Unfortunately we can get into
trouble with IF's at the end of macros, for much the same reason
that RETURN can get into trouble (see section The Command Interpreter).
The symptoms are that a macro either gets the arguments that were passed to the
macro that called it, or complains that it can't handle numbered
variables at all because it isn't in a macro at all.
To avoid this, there is an explicit \n at the end of the macro check.

It is possible to redefine the values of arguments (it won't affect
the values you originally specified, arguments are passed by value),
or to DEFINE values for arguments that you didn't declare. The
latter case allows you to have temporary variables, local in scope to
the macro.


An example is the rel macro, which is defined as

rel  2  DEFINE 1 ($1) DEFINE 2 ($2) RELOCATE $1 $2


which allows you to specify expressions to the relocate command.
For more examples see the `useful macros' section.





Newlines are allowed within macros, and as usual
any text from a # to the
next newline is taken to be a comment. If a # is needed within a
macro, escape the # with a \ or enclose it in double quotes.
If a macro starts with a comment the comment will not affect the
macro's speed of execution. Macros starting with ## are
treated specially by SAVE (they are not saved) and MACRO LIST

(they are not listed if VERBOSE is 0).





If the macro command is given as

MACRO name { DELETE }


or

MACRO name DELETE


the macro will be deleted (you can also delete a macro from the macro
editor by specifying a negative number of arguments).
If the name is already
defined, it will be silently redefined. Macros may be nested freely, and even
called recursively.
For example, the definition

MACRO aa {aa}


is perfectly legal, but SM will go away and think about it
for ever if you ever type aa (or at least until you type control-C.)
The definition

MACRO zz { zz zz    # comment: not recommended }


is also legal, but in this case if you execute it SM
will fill its call and macro stacks
and complain when it grabs more space. As
before, it will think about it forever. More useful examples of
recursive macros are compatible (see section Tips for Mongo Users), which starts

IF($?1 == 0) { compatible 1 RETURN } ...


providing a default value for its argument, and repeat which is
discussed under DO.



To find how a particular macro is defined, type HELP macroname.



For
a listing of the first line of all currently defined macros, type

LIST MACRO


or

LIST MACRO x y


The optional x and y are the alphabetical (actually asciial ) range of
macro names to list. As mentioned above, if VERBOSE is 0, macros
starting with ## are not listed by this command. There is a
macro ls defined as DELETE HISTORY LIST MACRO which will
list macros without appearing on the history list. (Or you could
overload list; see under overload in the index).







A related command is APROPOS pattern which lists all macros and
help files(13)
whose names or initial comments contain the pattern, for example

APROPOS histogram


would list bar_hist and get_hist as well as the
abbreviations hi and hist. If you wanted to find all
macros starting with a single comment character which mentioned

histogram you could say

APROPOS "^#[^#] .*histogram"


where the double quotes prevent the #'s being interpreted as
comment characters.

APROPOS ^[a-z]


will list all macros beginning with lowercase letters -- this is
similar to MACRO LIST a z, but pays no attention to the value of

VERBOSE.



It is also
possible to read macros in from disk, and in fact when SM is started,
it tries to read the file `default' in the directory specified by
macro in the environment file `.sm'. The command to read a
file of macros is

MACRO READ filename


Any line with a # in the first column is treated as a comment, and is
echoed to the terminal if VERBOSE is greater than zero.



All the currently defined macros may be written to a file with
the command

MACRO WRITE filename


If the file exists, it will be overwritten (under VMS, a new version of
the file will be written).
Macros are written out
in alphabetical order.


The command

MACRO WRITE macroname filename


writes the macro macroname to the file filename.
This command remembers which file it last wrote a macro
to, and if the current filename is the same then it appends the macro
to the end of the file, otherwise it overwrites it (or creates a new
version under VMS)
unless the filename is preceded by a +,
in which case the macros will always be appended.
This allows a set
of related macros to be written to a file.

MACRO DELETE filename


undefined all macros which are defined in filename.
This allows a file of macros to be read in, used and forgotten again.
The difference between this command and MACRO macroname DELETE
should be noted.
The SAVE command is probably a better way of saving all current macros.
The format of macros on disk is name nargs text, where

nargs may be omitted if it is 0. Continuation lines start with a
space or tab. See the files in the directory specified by macro in your `.sm' file for examples.





It is possible to define macros from the history list. The command

MACRO name i j


defines a macro name to be lines i to j inclusive of the history list,
as seen using HISTORY.


The opposite of this command, which places a macro upon the
history list, is WRITE HISTORY name. Examples of these commands are the
macros playback and edit_hist given in the section `A
Simple Plot'. This way of defining macros can
be convenient if you have created a useful set of commands on the
history buffer, and now want to save it in a macro and go on to other things.
Editing the playback buffer, and then changing its name to something
else (see next paragraph) is a convenient way of saving it that
implicitly uses this command.





Macros may be edited, using essentially the same keys as described
above for the history editor.
The command MACRO EDIT name starts up the
editor, which works on one line at a time.(14)
The zeroth line has the format

0> Macro name : Number of arguments: n


where name is the name of the macro, and n is the number of arguments to the
macro. If this line is
changed, except to change name or n, any changes made to the
macro will be ignored (note that the space after name is
required). This can be useful if you decide that you
didn't want to make those changes after all. Changing name or

n has the obvious effect, except that if n is negative the
macro is deleted when you exit the editor. An empty macro is also deleted
when you leave the editor (i.e. one with no characters in it, not even
a space).
The first line that you are presented with is the first line in the macro
rather than this special one.
Use control-N (or
) to get the next line,
control-P (or
) to get the previous line. Carriage return
(control-M) inserts a new line before the cursor, breaking the
line in the process, while control-O inserts a new line before
the current line.
To save the
changes and return to the command interpreter use control-X.
All other
keys have the same meaning as for the history editor (e.g. control-A to
go to the beginning of a line).
Note that control-K and control-Y can be used to copy lines, and
that the bindings can be changed with EDIT or READ EDIT.



It wouldn't be hard to write a macro that wrote out a macro to a file,
invoked your favourite text editor, then read the new definition back
in; see the macro emacs_all for ideas.




It is sometimes convenient to define a key to be equivalent to typing
some string, such as playback or cursor. This can be done
with the KEY command, whose syntax is KEY key string.
If you just type KEY <CR> you'll be prompted for the key and
string. In this case you are not using the history editor to read the key,
and you can simply hit the desired key followed by a space and the
desired string, terminated by a carriage return. If you put KEY,

key and string on one line you'll probably have to quote
the key with control-Q or ESC-q, or write the escape sequences
out in the way used by EDIT. If this sounds confusing, here is
an example. Type KEY<CR>, then hit the PF1 key on your terminal,
type a space, and type "echo Hello World\N". Now just hit the
PF1 key and see what happens. (The closing \N meant `and put a newline
at the end'). These keyboard macros are not generally terminal
independent, but they can be convenient. Definitions for the `PF' keys
on your keyboard can be made in a terminal-independent way by
specifying the key as pfn or PFn where n is 1, 2, 3,
or 4.
If you always use the same
terminal you might want to put some KEY definitions in your private
startup file (see the discussion of startup2 in the section on
useful macros). The current KEY definitions are listed with the

LIST EDIT command, along with the other key bindings.

DO and FOREACH loops, WHILE loops, and IF statements



Related to the macro facility are the DO, FOREACH,
and WHILE commands.

IF is included here as a flow-of-control keyword.



The syntax for a DO loop is

DO variable = expr1 , expr2 [ , expr3 ] { command_list }


where the third expression is optional, defaulting to 1. The value of variable
($variable) is in turn set to expr1, expr1+exp3, ...,

expr2, and the
commands in command_list executed. Changing the value of $variable
within the command list
has no effect upon the loop. Do loops may be nested, but the name of
the variable in each such loop must be distinct. A trivial example
would be

DO val = 123, 123+10, 2 { WRITE STANDARD $val }


while a more interesting example would be
the macro square discussed in the section on examples.



For loops within macros, it's often a good idea to make the loop variable
local: DEFINE val LOCAL DO val ... (see section Define).



Because the body of the loop must be scanned (and parsed) repeatedly, loops
with many circuits are rather slow. If at all possible you should try
to use vector operations rather than DO loops.

For example the loop

DO i=0,DIMEN(x)-1 {
     IF(x[$i] >= 0) {
        SET x[$i]=SQRT(x[$i])
     } ELSE {
        SET x[$i]=0
     }
}


is better written as

SET x=(x >= 0) ? SQRT(x) : 0


where the ternary operator ?: is discussed in the section on vectors
(see section Vectors and Arithmetic). If you only wanted the elements with x >= 0,
you'd have said

     SET x=SQRT(x) if(x >= 0)
}



As an alternative to DO loops, SM also has a general looping command, a
while loop, for example

set i=0
while {i < 10} {
        commands
        set i=i+1
}


is equivalent to a DO loop. In addition to being more flexible,


WHILE loops may also be interrupted with the BREAK command, so the
previous example could have been written (using variables instead of
vectors)

define i 0
while{1} {
        echo Hi $i
        define i ($i+1)
        if($i == 10) { break }
}



Foreach loops are similar to do loops, with syntax

FOREACH variable ( list ) { command_list }


,

FOREACH variable { list } { command_list }


, or

FOREACH variable vector { command_list }


where the list may consist of a number of words or numbers.
a vector.
Each element in the list (or of the vector) is in turn defined to be the
value of
$variable, and then the commands in command_list are executed,
so that for example the commands:

FOREACH i ( one 2 three ) { WRITE STANDARD $i }
SET str = {one 2 three}
FOREACH i str { WRITE STANDARD $i }


will print out:

one
2
three


twice.
Foreach loops may be nested, but again the variables must be distinct.
You can delimit the list with {} so that it can include
keywords (and other things that you want treated as strings such as 0.1

or $date), but even then you can't have the word delete in the
list of a foreach. Sorry.

It's often helpful to make the foreach variable LOCAL (see section Set)
inside macros, e.g.

DEFINE var LOCAL  FOREACH var ...



If statements look similar, with syntax

IF ( expr ) { list } ELSE { list2 }


where the ELSE clause is optional, but if it is omitted the closing
} must be followed by a newline (or explicit \n)
(see section The Command Interpreter).



If the (scalar) expression is true (i.e. non-zero), then the commands

list are executed, otherwise list2 is, if present. It is also
possible to use IF statements directly in plotting commands, for
example POINTS x y IF(z > 1/x).



You can use logical operators within the expr (see section If).
Note that && and || do not`short-circuit'; that is,
in the expression expr1 && expr2 both expr1 and expr2

are evaluated. In a scalar context (e.g. in an IF statement), the operators
AND and OR are available instead, and they do only evaluate
the right hand side if it's value is required.



It is possible to write general loops in SM by using of tail-recursive macros.
(15)
The simplest example would be

macro aa {echo hello, world\n aa}


which prints hello, world and then calls itself, so it prints
hello, world and then calls itself, and so on until you hit control-C.
The absence of
a space before the closing brace is very important, as it allows SM to
discard the macro before calling it again, which means that it won't fill
up its call stack and start complaining. A more interesting example is
the macro repeat which repeats a given macro while the given
condition is true. For example, if you say

macro aa { set i=i+1 calc i }
set i=0 repeat aa while i < 10


it will print the integers from 0 to 9. With a few checks, bells, and whistles
the macro looks like:


repeat 103      # Repeat a macro `name' while the condition is true
                # syntax: repeat name while condition
                # Example: set i=0 repeat body while i < 10
                if('$2' != 'while') {
                   echo Syntax: $0 macro while condition
                   return
                }
                if(int((whatis($1)-4*int(whatis($1)/4))/2) == 0) {
                   echo $1 is not a macro
                   return
                }
                macro _$1 {
                   if(($!!3) == 0) { return }
                   $!!1
                   _$!!1}
                _$1
                macro _$1 delete


and is one of SM's default macros (type "help repeat" if you don't
believe me).

The Help Command




There is an online help command. Typing HELP <CR>
or HELP HELP
gives a list of the help menu, or HELP keyword gives help with that keyword.
The help menu consists
of any files in the directory specified by the entry help

in the environment file, so for example HELP data types
the file data in that directory. For all cases except HELP help, the
file is filtered through a version of the Unix utility `more' which pages
the file. When `more' offers you a `...' prompt, type ? to see your
options.


The same filter is used by e.g. LIST MACRO .
If the command is HELP word, after HELP tries to print the file
word, it looks to see if word is a macro, and if so prints
its definition. If word is a variable, its value is then
printed, and if word is also a vector HELP





prints the dimension, followed by the help
string associated with the vector
vector_name (see section on vectors).



The APROPOS command is also useful when you need help.
APROPOS string scans all the help files (if your operating
system allows SM to do such things) and macro headers looking for the
string. The string may actually be a pattern (see the description
of APROPOS for details). If VERBOSE

(see section Verbose) is zero only
the lines from the help files matching the pattern are printed; if
it is larger you are given a couple of lines of context on each side.



It is worth remembering that the index to this manual has an entry
under weird, wherein are listed all sorts of strange happenings,
with explanations and suggestions for workarounds.

Saving and Restoring a Session






If for some reason you want to stop a SM session for later
resumption, and simply suspending the process, `control-Z', is not
sufficient, (for instance the machine is going down), then the SAVE command will write a file containing all your currently defined
macros, variables, and vectors, along with your current history buffer
as the macro all. You will be prompted before each class of
objects is saved, or you can put the answers on the command line.
The file is ascii, and can be edited if you so
desire. The filename defaults to `sm.dmp' if not specified, or to
the value of save_file from your `.sm' file.


If some bug has crawled unbeknownst to us into SM, and results
in some sort of panic (such as a segmentation violation), a save file
called `panic.dmp' is written to your temporary directory, no
questions asked.



To restart, RESTORE filename will read them all back, using the
same default file as for SAVE if no filename is specified, and
replace the current history buffer with the value of all

from the savefile. Of course, you could write a macro to preserve the
current buffer (see the definition of edit_all for hints).
If the file wasn't written by SAVE it is assumed to be a
SM history file, one of those written when you quit SM, and
each line is assumed to be a command and written to the end of the
history buffer. This is generally useful when you started SM
in the wrong directory. It wouldn't be hard to write a macro to use
RESTORE to read a history file into a macro.



One problem with SAVE is that it saves lots of macros,
including some of the system ones. Specifically, all macros are saved
except those beginning with "##".
This can be avoided with
the MACRO DELETE filename command, e.g. MACRO DELETE utils
SAVE 1 1 1 MACRO READ utils
.
The macro sav discussed under `useful macros' will do this for
you, and indeed not SAVE any macros that have been read with the

load macro. This is probably the best way to use the SAVE
command. In addition, sav also decides to save variables and
macros, only prompting you about saving vectors. sav is a good
candidate for overloading (as save), and indeed is one of the
macros redefined by the set_overload command.

Vectors and Arithmetic


The basic unit of data in SM is the `vector', a named set of one or
more numbers or strings. There is no limit to the number of vectors
that may be defined. SM allows the user to read vectors from files or
define them from the keyboard, to plot them and to perform arithmetic
operations upon them. SM's string-valued vectors are less generally useful,
but can be used
for such purposes as labelling points on a graph.



To read a vector vec from a column of numbers in a file, where the
filename has been specified
using DATA and, possibly, the range of lines in the file to be used
has been specified using the

LINES command, use READ vec nn where nn is the column number,
or READ { vec1 n1 vec2 n2 ... } to read many vectors.
It is also possible to read a row, using READ ROW vec nn, where nn is
the row number in the file. See READ for how to read a
string-valued vector.



Instead of using simple column-oriented input
it is possible to specify a format like those used by C's scanf
functions (Fortran formats are not supported); if you provide your own
format string you can only read numbers.
For example, if your data file has lines like

	1:12:30  -45:30:11


you could read it with
read '%d:%d:%d %f:%f:%f' { hr min sec deg dmin dsec }.


A vector may also be defined as SET vec = x1,x2,dx to take on
the values x1,x1+dx,...,x2, where dx defaults to 1
if omitted. If a scalar is
encountered where a vector is expected, it is promoted to be a vector
of the appropriate dimension; all other dimension mismatches are
errors. Example:


SET value = 5
SET x = 0, 50, 2
SET y = x
SET y = x*0 + value
SET y[0] = 2*pi
SET y = value
SET x=0,1,.1 SET y=IMAGE(x,1.5)
SET s=str
SET s='str'
SET s[0]=1.23
SET x=1.23
SET s=x
SET s=STRING(x)

will define a scalar, value, with a value of 5, then define a vector,
x, with 26 elements, valued 0, 2, 4, 6,..., 50, then define another
vector, y with size 26 and the same values as x,
set all 26 elements of y to have the value 5,
set the first element of y to be 2 pi,
set y

to be a vector with one element with value 5, and finally
set y to be a vector with the values taken from a horizontal
cross-section from 0 to 1 through the current image. Unless a vector
str is defined SET s=str is an error; to make s a
string-valued vector use SET s='str'.

SET s[0]=1.23 makes s[0] have the value "1.23" (a string),
as s is now a pre-existing string vector.
An arithmetic vector x is then
defined, and s is redefined as an arithmetic vector too -- you must
be careful when dealing with string vectors! Finally, we explicitly
convert an arithmetic vector to a string-valued one with the STRING

operator.
This is a somewhat
contrived example, designed mainly to illustrate the convenience of the
SET command. The ability to set particular elements is mostly
used in macros such as smirnov2 which calculates the
Kolmogorov-Smirnov statistic from a pair of vectors.



If you don't have many data points, rather than type them into a file, and use
READ vec nn to define a vector, you can use the command

SET vec = { list } 


For example

SET r = 0,10 


is equivalent to

SET r = { 0 1 2 3 4 5 6 8 9 10 } 


In fact, { list } is an expression, so

SET vec = 2*{1 3 1} is also legal.
If the first element of a list is a word, the vector is taken to be
string-valued: SET s={ William William Henry Steven } defines a
4-element string vector, or you can use a string in quotes:
SET s=<'1' 2 3 4> (if you used SET s={'1' 2 3 4} the first
element would be '1' rather than 1).
Once a vector is defined, you can write it to a file for later study using the

PRINT command.



A scalar may be an integer, a floating point number, a scalar
expression, DIMEN(vector), or WORD[expr]. The last two are the
dimension of a vector, and an element of the vector with expr a
scalar subscript. Note that subscripts start at 0 and that [ ]
`not' () are used to subscript variables
.
The expression WORD[expr] is in fact allowed even if expr

is not a scalar, in which case the result is a vector with the same
dimension as expr, and with the values taken from WORD in
the obvious way.



Once vectors are defined, they may be combined into expressions using

the operators +, -, *, /, **,

CONCAT and the
functions COS(), SIN(), TAN(), ACOS(),
ASIN(), ATAN(), ATAN2(), ABS(), DIMEN(), INT(), LG(), EXP(), LN(),
SQRT(), STRING(), STRLEN()
, and
SUM().
The meaning of most of these is obvious, ATAN2 is like ATAN
but takes two arguments, x and y and returns an angle in the
proper sector.

DIMEN returns the number of
elements in a vector, SUM gives the sum of all the elements,
CONCAT concatenates two vectors,

INT gives the integral part of a vector, STRING
converts a number to a string, and STRLEN gives the length of a string
(in plotting units, not just the number of characters). STRING uses
the same code as the axis-labelling routines, so FORMAT can be used
to modify its behaviour; whether the x- or y-axis formats is used depends
on whether the label is more nearly horizontal or vertical.
An example would be

set x=3.08e16 define s (string(x)) relocate 0.5 0.5 putlabel 5 $s




The precedence and binding are
as for C (or Fortran), and may be altered by using parentheses
(CONCAT has a binding just below + and -).
All of these operators work element by element, so


y = 2 + sin(x)


is interpreted as


If there is a size mismatch the operation will only be carried out up
to the length of the shorter vector and a message is printed; if
VERBOSE is 1 or more, the line where the error occurred will
be printed too.
The constant PI is predefined.


You can also use WORD([ expr [ , ... ]]) as part of
an expression, where WORD is a macro taking zero or more arguments.

Suppose we define a macro pow with two arguments as

SET $0 = $1**$2 


then the command

SET y = 10 + 2*pow(1 + x,3)


is equivalent to SET y = 10 + 2*(1 + x)**3.



In addition to these arithmetic operations, there are also logical
operators == (equals), != (not equals),

>, >=, <, <=, &&
(logical and), and || (logical or). The meanings of the symbols are the
same as in C, and as in C the value 0 is false while all other values are true.
Note that && and || do not`short-circuit'; that is,
in the expression expr1 && expr2 both expr1 and expr2

are evaluated. In a scalar context (e.g. in an IF statement), the operators
AND and OR are available instead, and they do only evaluate
the right hand side if it's value is required (see section If).



String vectors may only be concatenated, added, or tested for (in)equality.
Adding two string-valued vectors concatenates their elements, so

{ a b c } + { x y z }

results in the vector ax by cz.



Testing equality for string vectors seems to cause some confusion. Consider

set str=<'a' b c d>
if('a' == 'str') {     # test if the strings `a' and `str' are equal
if('a' == str) {       # test if the string `a' equals the vector `str'
if(a == str) {         # test if the vector `a' equals the vector `str'


The second of these tests will succeed, but if you then try

if('b' == str) {       # try to see if `b' is an element of str


the test will fail as 'b' == str is the 4-element vector
{ 0 1 0 1 } and only its first element is used by the if test;
what you want is

if(sum('b' == str)) {  # is `b' an element of str?


There are also a number of less mathematical operations. If you have an
IMAGE (see section Image) defined, you can extract a set of values
using the expression IMAGE(expr,expr), where the two exprs
give the coordinates where the values are desired. Note that this may be
used as a way of reading large data files that are stored unformatted.
The expression HISTOGRAM(expr : expr) can be used to convert a
vector into a histogram. The second expression is taken to be the
centres of the desired bins: bin boundaries are taken at the mean points
(and points in the first expression lying on a boundary are taken to
fall into the lower bin. Note the use of `:' not `,').



Vectors may be assigned to, using the syntax

SET vec = expr


or

SET vec[ expr ]  = expr


or

SET vec = WORD(expr)


or

SET DIMEN(vec) = number


or

SET vec = expr1 IF(expr2)


or

SET  vec = expr1 ? expr2 : expr3


The first form sets vec to have the value expr, element by
element, vec is the name of the new vector. The form
vec[expr] may be used to assign to an element of a vector, as usual
the index starts at 0. Before you can use SET to assign values to the
elements of a vector, you must create it using one of the other forms
of the SET command.



If you want to define a vector to which you will subsequently assign values
using SET vec[ expr ] = expr, you may use SET DIMEN(vec) = number
which declares vec to be a vector of size number, and
initialises it to zero. You can optionally supply a qualifier to the
number, either a .f (the default), or a .s to
specify that the vector is string valued.




If the IF clause is present, only those
elements of expr1 for which the corresponding element of expr2 is
true
(non-zero) are copied into vec; in general vec will have a
smaller dimension than expr1. The last SET statement (with ?:)
again borrows
from C. If expr1_i is true, then vec_i is set
to expr2_i, otherwise it is
set to expr3_i. In this form of conditional assignment, the dimension
of vec is the same as that of the right hand side. It may look
strange, but it can be just what you want.




Each vector also has a help field, which may be used to provide a string
describing the vector. The field is set by

SET HELP vec str


and
viewed by

HELP vec


or via the string-valued expression HELP(name).



If VERBOSE is one or more, if a vector is arithmetic or string
will also be noted. Vectors may be printed using the

PRINT [ file ] [format] { vec1, ..., vecn }


command, where if the optional
file is missing, the values are typed to the keyboard; if the
optional format is omitted, a suitable one will be chosen for you.
Any combination of string- and arithmetic-vectors may be printed.
If a value
exceeds 1e36, it is printed as a *. This is consistent with the
convention used in reading data that a `missing' number is represented
as 1.001e36; see READ for details.
Vectors may be deleted with the command

DELETE vec


and listed with the command

LIST SET




Vectors are listed in ascii order along with their
dimension, and any help string specified using the SET HELP command



Once you start writing (or using) complicated macros you'll get bitten by
the fact that a macro called by a macro called by a friend's macro uses
a scratch vector called x or i, and that this vector quietly
overwrites your vector called x or i. To avoid this,
conscientious macro writers make their vectors LOCAL.
(16).
After the command SET x LOCAL in a macro, any redefinitions of x

within that macro, or any macros called by it, will be discarded when the
macro exits. The vector isn't strictly speaking local to the macro as it's
visible from macros that are more deeply nested, but the effect is similar.
A word on caution: a macro can exit sooner than you expect; the classic
example is

cube     11      # print a vector's cube for people we like
                 define name local  define name :
                 if('$name' != 'Thatcher') {
                        set x local  set x = $1
                        set x = x*x*x
                        print The answer is $(x)
                 }


Because the if might be followed by an else, the macro is
read and popped from the input stack before it's executed, causing
confusion.


An IF clause has been
added to the plotting commands, to allow only those elements of a
vector which satisfy some condition to be plotted, for example

POINTS x y IF(z > 3*x)


Of course, you could have used the IF command and the regular
POINTS command if you had preferred. In fact,

CONNECT x y IF(z > 3*x)


isn't quite the same as

SET log = z > 3*x SET x = x IF(log)  SET y = y IF(log) 
CONNECT x y


as the former will only connect contiguous points.

Drawing Labels and SM's TeX Emulation





There are two separate ways to specify special characters to
SM, by using a syntax
very similar to TeX (the type-setting system created by Donald Knuth
that we used for this manual), or the traditional Mongo way. You might
ask what are the advantages
of TeX? One is that sub- and super- scripts are handled much more naturally,
making it much harder to type
when you meant
Another is that you no longer have to remember that
is hidden
in the Greek font as `q', you can simply type \theta. A
third would be that you may well know TeX already.



If you want to make SM understand TeX strings
you should define the variable
TeX_strings (if you put a line

TeX_strings 1 in your `.sm' file this will be done automatically).

You can, of course, undefine it at any time to revert to the old-fashioned
strings described below.

Using TeX-style
strings is strongly recommended by the authors; all future and most
recent improvements to SM's labels are only supported in TeX mode.



If you want to change the default font used for labels, define the variable
default_font; if you wanted to use the \oe (Old English)
font you could either say (DEFINE default_font oe) interactively,
or put a line in your `.sm file': default_font oe.
This affects axis as well as regular labels and
only works if you use TeX_strings (of course).



For some devices with hardware fonts (for example, postscript printers
or a Tektronix 4010 terminal), if expand is exactly 1, and
angle is exactly 0, the hard fonts will be used for speed.
Various strategies to defeat this are discussed below.

  • TeX Control Sequences: SM's TeX Control Sequences
  • TeX Extensions: SM's Extensions to TeX
  • Caveats: Caveats and Cautions when using TeX
  • Defeating Hardware Fonts: How to Stop the Device using its Fonts
  • Old Labels: Old-style Labels
  • An Introduction to TeX


    (TeXsperts should skip this section.)
    If you don't know TeX
    let's start with an example:

    label \pi^{\-21/2} = {\3\int}e^{-x^2}\,dx
    


    will print a well-known result (You'll have to RELOCATE somewhere
    where the label will be visible first, of course).
    (If
    you want to try it now, you should be careful typing those ^'s, as
    they are special to the history editor, dealing with this is
    discussed below.) In
    this example the characters \, {, }, and ^

    are special (and so is _ which wasn't used). Postponing \
    for the moment, ^ means `make the next group a superscript',
    _ means `make the next group a subscript', where a group is
    either a single character, a single control sequence (wait a moment!), or a
    string enclosed in braces. So A_a^{SM}B would appear as
    A \ can serve one of two functions, either
    turning off the special meaning of the next character (so \_

    is simply a _ with no special significance), or to introduce a
    named `control sequence'. These fall into three groups, those that
    change fonts, those that serve as abbreviations for single
    characters (e.g. \pi in the example), and those that are macros.
    The font changes persist
    until the end of the string, or the current group, whichever comes
    first.

    Available Fonts


    The available fonts are
    `greek', `old english', `private', `roman', `script', and `tiny'. They
    may be referred to either by a
    two-character control sequences (\gr, \oe, \pr,

    \rm, \sc, or \ti) or simply by the first character
    (e.g. \r for the roman font).
    In addition \i or \it
    can be used to make the current font italic (remember to use italics
    within {} so that their effect is limited!).
    The `bold' font \b or \bf is makes the current font bold,
    and can be toggled off with a second

    \bf if you didn't simply group it. I'd strongly recommend
    treating \bf like any other font change, and
    group them rather than relying on this toggling action.



    The slant of \it letters can be controlled by the command sequence
    \slant, which takes an argument which is the tangent of the desired
    slope (i.e. it is the degree of shear). You can also compress all letters
    along the direction that they are being written using \condense; for
    example {\slant0.4\condense0.5 Hello World}.



    You can alter the size of the letters
    by using an escape such as \6 which scales the current group
    (any font change is local to a group).
    \6 corresponds to multiplying the size by
    or
    about 3, \-4 scales by
    or 0.48. This is similar to
    the `magstep' used in scaling fonts in TeX.
    These scale factors
    are in addition to the expansion produced by going
    up or down (^ or _), or setting EXPAND.

    SM's TeX Control Sequences


    Other control sequences either consist of one non-alphabetic
    character, or else a name consisting only of letters, so \, or
    \palmtree is valid but \one2three is not. If a
    alphabetic name is followed by a space, the space is treated as simply
    delimiting the name and is discarded. For example,

    AB^{\alpha_\beta CD} will appear as
    (note that the space after beta disappeared). How do you make
    just a few characters italic (script, old english, etc.)? Try
    ABC{\it DEF}GHI. You can't read a subscript, and want it in
    `tiny' font? Try \Lambda_{\ti ab}. All of the Greek letters are
    defined, as \alpha-\omega,\Alpha-\Omega,
    there are various mathematical symbols (e.g. \int, \infty,
    or \sqrt), some astronomical (e.g. \AA for
    and some
    miscellaneous characters (e.g. \snow to draw a snowflake).
    You can generate
    a complete list of definitions by saying load fonts TeX_defs.



    Some of these definitions are more complex than just special characters,
    if you know TeX most of them should be familiar.

    \bar str

    Draw a bar over str.
    \border n str

    Add an n-pixel border of whitespace to str and draw it.

    \centre

    \center

    Center a string horizontally
    \colour

    \ctype

    \color

    Change to the specified colour.

    \over str1 str2

    Draw str1 over str2, separated by a horizontal line. This isn't
    nearly as sophisticated as TeX's \over, and never will be.
    It's written in SM's TeX emulator which is pretty limited. If you are
    a LaTeX user, SM's \frac may be more familiar.
    \phantom str

    Don't actually draw str, but take up as much space as str

    would have if you had drawn it.

    \smash str

    Draw str but pretend that it took up no space.
    \strut

    Make the current formula have at least the depth and height of a parenthesis.


    You can also define your own TeX definitions by using the special
    command \def\name{value} inside a label. It produces no output,
    but defines name to expand to value. For example, I could define
    \TeX to produce TeX by saying

    LABEL \def\TeX{T\raise-200\kern-20E\raise200X}.
    


    Once a
    definition has been made it is remembered forever (well, until you
    leave SM actually) whatever devices you plot on. You must make sure that
    all curly brackets are properly paired inside your definition. You
    can have arguments just like real TeX, referred to as #1,
    #2, #3 and so forth, for example

    \def\sub#1{_{#1}}
    


    Your SM guru can compile TeX-definitions into the binary fonts
    file, instructions are given in the fonts appendix.

    SM's Extensions to TeX



    We have made a number of extensions to TeX that are useful in
    a plotting package, but wouldn't be especially valuable in a printed document.
    We have also distorted the meanings of some of TeX's control words; sorry.


    \point n s

    \apoint angle n s

    Insert a points (such as would be drawn with DOT) into a label. The
    string \point43 (or \point 4 3) will draw a point at the
    current position in the string, of ptype `4 3'. This sequence,
    from the \ to the 3, is treated as a single character as regards
    things like subscripts. If you want to specify an angle, use something like

    \apoint 45 4 0.

    \hrule width

    Draw a horizontal line at the level of the current baseline, of length
    width in screen units. It will be multiplied by the current
    expansion.

    \kern dx

    \kern # moves the current plot position by #

    horizontally, where the distance
    # is specified in screen units (the whole screen is 32768
    across). It is multiplied by the expansion currently in effect, and may be
    positive or negative. See also \raise.

    \line type length

    \line inserts a line into a label, at about the level of the
    middle of a lower-case character.
    e.g. \line 1 1000 will draw a line of length 1000 (in screen
    units, so the screen is 32768 across), of ltype 1.
    See also \hrule.

    \move dx dy

    Move a group by (dx,dy), but don't disturb SM's current idea of where
    it is. This means that we can draw a line over a character with a string
    such as \move 0 300{\line 0 400}A. It is possible to use the
    commands such as \width to take the guesswork out of such commands,
    for example the definition of \bar is

    \def\bar#1{\move0\advance\height{#1}by100{\rule\width{#1}}#1}
    
    

    \raise dy

    \raise # moves the current plot position by #
    vertically, where the distance
    # is specified in screen units (the whole screen is 32768
    across). It is multiplied by the expansion currently in effect, and may be
    positive or negative. See also \kern.

    \vrule depth height


    Draw a vertical line at the current position of depth d and
    height h (and width 0) in screen units. Dimensions are multiplied by
    the current expansion.


    There are also a number of control sequences that can be used whenever
    a number is expected (by \kern, \line, \move,
    or \raise);
    for an example of their use see \move in the preceding table.

    \advance num1 [ by ] num

    Increment first number (which can be of the form \width{...})
    by the second. The by is optional.

    \depth{...}

    The depth a group would have if it were drawn.

    \divide num1 [ by ] num2


    Divide the num1 by num2/1000. As for \advance,
    num1 and num2 need not be `simple' numbers but can be
    combinations of widths, advances, and so on. The by is optional.

    \height{...}

    The height a group would have if it were drawn.

    \multiply num1 [ by ] num2

    Multiply the num1 by num2/1000. See \divide for the
    lack of restrictions on num1 and num2. The by is optional.

    \width{...}

    The width a group would have if it were drawn


    If you want to know the dimensions of the string that you have just drawn
    (or just not drawn, q.v. PUTLABEL 0) you can look at the internal variables
    $sdepth, $sheight, and $slength.

    Caveats and Cautions when using TeX


    Now for a few caveats: Firstly, because \n is a newline, you must type
    \\nu or "\nu" to get a
    Secondly, the superscript
    character
    ^ is special to the history editor, so to type it interactively
    you must quote
    it with the quote_next key (usually control-Q or ESC-q, i.e.
    type control-Q^). Alternatively, you could change your history
    character to some under-used character such as % or ' (which is the
    solution that I use: you can choose a new character such as ' by
    simply putting a line

    history_char ' in your `.sm' file).

    Thirdly, TeX (and our pseudoTeX) are
    rather verbose and labels may not fit on one line. The solution is to
    continue the line by ending it with a \. This is probably best done
    within a macro, as the continuation line won't appear on your history
    list if typed at the prompt. You can currently have about 25
    continuation lines (2000 characters).



    A final point will only worry
    TeXies, namely that the emulation isn't perfect: for example
    \sum_i won't put the i beneath the summation symbol.
    Some of the other discrepancies were listed in the previous section.

    How to Stop the Device using its Fonts


    If EXPAND is set to exactly 1, and ANGLE is exactly 0, then SM
    will use hardware fonts, when available, in writing labels. This is faster,
    but can lead to two styles of labels in one plot which is ugly.



    There are various ways to trick SM into always using its own fonts:
    you can say say "ANGLE 360",
    or use a \0 to select a font with (explicitly) no expansion. To
    affect the axis tick labels too, using the AXIS or BOX commands,
    you'll have to say "EXPAND 1.0001" or somesuch.



    Rather than always expanding your plots, you could ask your SM
    Guru to edit the `graphcap' file to prevent a given device
    (usually a printer) from ever using hardware fonts. Tell her to
    see section The Stdgraph Graphics Kernel. If she won't oblige, you can define your own device in
    your own graphcap file, and put yours first in the `.sm' file.
    For example, my `.sm' file includes the line

    +graphcap    /d/rhl/graphcap
    


    and the file `/d/rhl/graphcap' looks like:

    # Private overrides for RHL:
    #
    postscript|postscript + no hardware fonts:\
            :TB@:TE@:TC=postscript:
    


    Then I set $printer to postscript (also in `.sm')
    and all is well.



    An alternative is to specify the device as

            DEVICE postscript :TB@:TE@:tc=postscript:
    


    which is perhaps simpler (you'd just define your value of printer
    properly).

    Old-style Labels


    If you insist on using old-style labels (which are still the default),
    here's a quick summary.
    Type \a or \\a
    to change to font
    a for one character (first form) or permanently (second
    form). The possible fonts are g, o, p, r, s, and t for
    `greek', `old english', `private', `roman', `script', and `tiny'
    respectively. In addition, the pseudo-fonts u

    and d move text `up' and `down' respectively, and i produces
    `italic' (actually just slanted) characters.
    Size changes are just like any other font change, so
    \6 and \-4 will affect one character and the rest of
    the string respectively.
    This is really somewhat simpler than it sounds - try

    label \gp\u\-21/2\2\d = \3\g:e\u-x\u2\d\s dx
    


    Note that `tiny' is a misnomer, it is (nowadays) just a font that
    look better if you need small letters (
    \t\-6 will produce a shrunken `tiny' font, just like the
    old days).
    Spaces are treated differently in different fonts, as a greek space is
    a negative space (i.e. a backspace), and a script space is only half as
    wide as a normal space.

    Getting Hardcopies of Plots




    There isn't really any need for this section because SM doesn't
    distinguish between hardcopy devices such as laser printers and
    other devices such as graphics terminals, except that it saves up
    plotting commands for hardcopy devices and sends them all when you are
    finished. There are, however, hard and
    easy ways to do anything and this section is intended to make your life a
    little simpler.



    When a device that can produce hardcopy is closed the plot is sent off
    to the printer (using the command given as SY in the device's
    graphcap entry). The only way to close a device is to open another, any
    other, so it is just as good to say dev x11 as it is to say

    hardcopy dev x11 as the macro hardcopy does no more than
    open the null device. So one way to produce a plot is to say

                    device postscript
                    plotting commands
                    device x11
    


    There are many different printers available, and even if you are using
    a postscript printer you might want portrait (postport) or
    landscape (postland) plots, so it is traditional to put the
    name of the desired printer into a variable printer. It is so
    traditional, indeed, that it can be done with a line such as

    printer     postport
    


    in your `.sm' file.



    The two commonest incantations are probably

                    device $printer
                    playback
                    device x11
    
    


    or

                    device $printer
                    my_macro
                    device x11
    


    which can be simplified to hcopy and hmacro my_macro respectively.
    The former
    can be given a single history number (e.g. hcopy 12) to only make
    a hardcopy
    of the one command, or a range of numbers (hcopy 1 12) to plot
    those lines (inclusive).
    The latter, if you omit the name of the macro, will prompt you to create
    a temporary macro that is then printed. If you want to make a hardcopy of
    the last line you have a choice, either hcopy -1 or hmacro,
    and then use the history editor to retrieve the desired line.



    Some sites have many hardcopy devices of the same type, in which case
    they usually set up the SY command to expect an argument
    which is the name of the desired printer. You can deal with this by including
    it in your printer variable: define printer "postscript latypus"
    but this can be a nuisance, especially as unix already has a special
    (environment) variable PRINTER that specifies your default printer.
    The resolution is that both hcopy and hmacro are quite
    careful; if you have an SM variable PRINTER it is taken to be your
    default printer; if you don't have one they look for one in your

    `.sm' file, if they don't find one there they look for an
    environment (VMS: logical) variable. If all of these fail they take the
    first argument (hcopy) or last argument (hmacro) to be the name
    of the printer.



    So if you have a PRINTER variable anywhere, hcopy and

    hmacro macro_name will work as before, if you don't then you'll have
    to say hcopy printer_name or hmacro macro_name printer_name.

    Overloading Keywords



    Sometimes you might wish that SM's authors had decided to make
    a command behave a bit differently, for instance that ERASE or
    QUIT didn't appear on the history list, or that SAVE deleted
    all the system macros before saving your environment. Of course, you can
    (usually) write macros to get around these annoyances, but you can't easily give them the same names as the original commands (for these
    examples the macros are called era, q, and sav).



    It is possible to change the meaning of keywords (to `overload' them),
    but it can be confusing, primarily because your
    new commands may not behave the same way that this manual claims.
    For example, if you were perverse, you could define points
    to mean QUIT. Another danger is that you could end up with a
    recursive call -- for instance if you wrote your own version of box that did all sorts of cunning things, then drew a box. If you
    said box in your macro, then overloaded the keyword, you'd have
    a macro that called itself. If you tried to use it, nothing would
    happen for a while, and then you'd start getting messages about "extending
    i/o stack" until you hit control-C. Or if you redefined help to mean

    DELETE HISTORY HELP (in upper case to avoid recursive calls, and
    in case delete has been overloaded), then set help vec Help string
    won't work (you'd have to use set HELP vec ...).



    Despite these warnings, overloading the meaning of
    SM's keywords can be very convenient. There are two sets of
    system macros that do just this, the compatibility ones (see section Tips for Mongo Users),
    and one called set_overload that is described below.



    In addition to the semi-trivial use of overloading to allow you to type
    erase not era, it is possible to add extra functionality
    to simple commands. For example, set_overload defines window
    to save the window parameters in variables, and box then uses these
    values to label appropriate axes in touching boxes. Another example is that
    (when overloaded) lines saves the line numbers used, so that you
    can write a macro to print the top 10 lines of a file (it's called head).



    So how do you do it? The command OVERLOAD keyword # will remove
    the special meaning of lowercase keyword if # is
    non-zero, or reinstate it otherwise. You can still use the uppercase form
    -- you can't overload that. So now that e.g. box has no
    special meaning you can define it to be a macro. What the set_overload macro does is to define new meanings for a number
    of keywords, the new definitions are in the macro file `overload'.
    If you intend using them (and I do all the time) you should look at
    this file.
    You can get them loaded by default by having a line overload 1 in your

    `.sm' file.

    If you don't like some, e.g. box, you can simply say OVERLOAD
    box 0
    in your private startup file (see `private initialisation')
    which is run after the system startup.



    Most of the changes are benign, but not all. For example, the
    new definition of relocate allows expressions, but it'll break
    if you try to say relocate ( 100 1000 ) to move to absolute
    screen coordinates. You can still say RELOCATE ( 100 1000) of
    course, and that's why most of the system macros are actually written
    in uppercase. The definition of box (actually bo,
    which box calls) may seem very complex, but
    it has to deal with box \n as well as box 1 2, and it
    must know if you have used the WINDOW command.
    This brings up another point -- if you overload keywords,
    you could slow SM down. It isn't that overloading is
    inefficient, it's just that the macros that replace the old keywords
    may do a good deal of work, box is a case in point. Even when
    the macro is short and to the point, it's still extra work to parse
    the original word and find its value as a macro.

    Examples of Useful Macros





    When you start SM the directory specified as macro in your
    `.sm' file is searched for a file `default', and then the
    macro startup from that file is executed. At the time of writing of
    this manual, startup was defined as:

    startup      ## macro invoked upon startup
                 FOREACH 1 { default_font device edit file_type history_char \
                        macro macro2 overload printer prompt prompt2 SHELL } {
                    DEFINE $1 :
                 }
                 FOREACH 1 { TeX_strings case_fold_search fan_compress \
                     line_up_exponents noclobber overload \
                     remember_history_line traceback uppercase } {
                    DEFINE $1 :
                    IF($?$1) {
                       IF('$$1' == '0') {
                          DEFINE $1 DELETE
                       }
                    }
                 }
                 IF($?prompt) { PROMPT $prompt\n DEFINE prompt DELETE
                 } ELSE { PROMPT : }
                 IF($?device) { DEVICE $device
                 } ELSE { DEFINE device nodevice }
                 IF($?default_font && $?TeX_strings == 0) {
                    echo You can only define a default font if you use TeX
                 }
                 IF($?history_char) {   # use $history_char as history character
                    IF('$history_char' != '0' && '$history_char' != '1') {
                       EDIT history_char $history_char
                    }
                    EDIT ^ ^
                    DEFINE history_char DELETE
                 }
                 # load the default macros
                 DEFINE mfiles < stats utils > # $mfiles is used by `sav'
                 FOREACH f ( mongo $mfiles ) { MACRO READ "$!macro"$f }
                 FOREACH var ( x_col y_col data_file ) { DEFINE $var . }
                 # load uppercase if defined in .sm file
                 IF($?uppercase) {
                    MACRO READ "$!macro"uppercase
                 }
                 # and overload keywords such as erase, if so desired
                 set_overload $?overload
                 # and some keymaps
                 IF($?edit) { READ EDIT "$!edit" }
                 # and an optional macro file, with macro startup2
                 IF($?macro2) {
                    MACRO READ "$!macro2"default
                    IF(is_set(startup2,1)) { startup2 }  # startup2 is defined
                 }
                 # provide a \n after the IF
    


    As this macro is executed every time that you run SM, let us consider
    it in some detail. After setting the prompt, it looks for entries for
    a number of variables in your `.sm' file. Some (such as printer)
    are simply DEFINEd, while some (such as TeX_strings)
    are only DEFINEd if they
    have a non-zero value. Because some of the values might not be numeric,
    the comparison is forced to be done on strings by enclosing the quantities
    in single quotes.
    An entry prompt is interpreted as a primary prompt, mostly for
    compatibility with the use of $prompt2 to set the secondary prompt.
    If device is defined it is used to set the default plotting
    device, and both it and printer are used by a couple
    of macros (hcopy and hmacro) that produce hardcopy.
    The variables

    TeX_strings and default_fonts are used in producing
    labels (see section SM's Fonts).
    Because TeX uses ^ for superscripts, we
    allow you to put a history_char line in `.sm' to specify a
    character to use rather than ^ for history (I use `).
    If you use 0, or omit the value (so it is set to 1), no
    history character is defined to replace ^.
    The variable file_type is used by the IMAGE command to
    determine the file format that you use (e.g. C, or unformatted fortran).



    Startup doesn't have to check that macro was successfully
    defined as it must have been found for startup to have been read
    in the first place. Macro specifies where to look for macro libraries,
    and startup next sets the variable mfiles containing the
    names of some of


    the system macros to be loaded, and reads them.
    The macro load defined below also maintains the mfiles
    list, as does unload. It is used by the
    sav macro, which is discussed below the main listing of macros that
    follows.
    We also set some variables used by the id macro.


    As part of our effort to be nice
    to users, if you have uppercase 1 in your `.sm' file,
    we also load the uppercase macros.
    Next startup overloads some keywords if overload is
    in your `.sm' file, reads a file of keybindings (if edit

    is given in `.sm'), and
    finally tries to read a second optional macro directory
    macro2, and executes a macro startup2 if it's defined
    (that's what the macro is_set is checking).
    This is quite important, as it provides a way to customise SM
    to your personal taste without convincing the local SM guru
    that your taste should be foisted on everyone. If you want a prompt that
    is different, or a definition of q that just quits without asking
    questions, you can get them by using macro2.




    You can see that it is possible
    to tailor SM pretty much as you wish without changing a line of
    code, just by playing with the startup macro.



    SM provides various compatibility
    macros, and some to package often-used functions.
    The macro files `stats' and `utils', which are read when SM
    is started, provide various useful
    macros, a few of which are presented here. To see a current list, either
    look at the files directly, set VERBOSE to zero and list all the
    macros, look at the listing in this manual (see section The System Macro Libraries),
    or use lsm to list macro files
    (this only works if you are running Unix; try lsm demos).
    We give here a number of macros taken from the files `default',

    `mongo', `stats', and `utils'.
    Among those not listed are those like lin defined to be lines
    that are pure
    abbreviations, those like xlogarithm defined as
    SET x=lg(x) which provide functionality in a perhaps familiar form,
    and many more like those that are given here which provide
    enhancements (e.g. the macro barhist).
    A discussion of a few of the more interesting or obscure follows.
    Keywords are written in uppercase, because you might have been playing
    tricks with overloading the lowercase equivalents.
    Many of these macros, in fact all from `default' and `mongo',
    start with ## so as not to show up in listings made when VERBOSE is 0, and so as not to be SAVEd. In the interest of
    brevity we have omitted most of these initial comments.

    cumulate 2   # Find the cumulative distribution of $1 in $2
                 DEFINE sum 0 SET $2=0*$1 SET HELP $2 Cumulation of $1
                 DO i=0,DIMEN($1)-1 {
                    DEFINE sum ( $sum + $1[$i] )
                    SET $2[$i] = $sum
                 }
                 define sum delete
    da   1       DATA "$1"
    del1 1       DELETE HISTORY \n
    dev  1       del1 DEFINE device $1 DEVICE $1
    dra 2        # Draw, accepting expressions
                 define 1 ($1) define 2 ($2) draw $1 $2
    edit_hist    # Edit the history list
                 del1 MACRO all 0 100000       # define "all" from buffer
                 WRITE STANDARD Editing History Buffer\n
                 MACRO EDIT all                # do the editing
                 DELETE 0 100000       # empty history buffer
                 WRITE HISTORY all             # replace history by "all"
    era          del1 ERASE
    gauss 1      # Evaluate a Gaussian : N($mean,$sig)
                 SET $0 = 1/(SQRT(2*PI)*$sig)*EXP(-(($1-$mean)/$sig)**2/2)
    get 2        # Syntax: get i j.  Read a column from a file.
                 # Name of vector is jth word of line i.
                 DEFINE nn READ $1 $2 echo reading $nn\n
                 READ $nn $2
                 SET HELP $nn Column $2 from $data_file
                 DEFINE nn DELETE
    hardcopy     DEVICE nodevice   # close old device
    hcopy 13     ## hcopy [printer] [l1] [l2] Make hardcopy of playback buffer
                 # optionally specify printer ($1) and desired lines ($2-$3)
                 # if the printer ($1) is omitted (i.e. $1 is missing or a
                 # number), it will be taken from the value of the environment
                 # variable PRINTER, if defined.
                 IF($?printer == 0) {
                    DEFINE printer ? { what kind of printer? }
                 }
                 IF($?1) {
                    IF(WHATIS($1) == 0) { # a number
                       if($?2) { DEFINE 3 $2 }
                       DEFINE 2 $1
                       DEFINE 1 DELETE
                    }
                 }
                 IF($?1) {
                    DEVICE $printer $1
                 } ELSE {
                    IF($?PRINTER == 0) { DEFINE PRINTER : } # which one?
                    IF($?PRINTER) {
                       DEVICE $printer $PRINTER
                    } ELSE {
                       DEVICE $printer
                    }
                 }
                 IF($?2 == 0) {
                    DEFINE 2 0 DEFINE 3 10000
                 } ELSE {
                    IF($?3 == 0) { DEFINE 3 $2 }
                 }
                 playback $2 $3 \n DEVICE $device
                 bell
    hmacro  12   ## hmacro [macro] [printer] Make hardcopy of a macro
                 # If only 1 argument is present, it is taken to be the printer
                 # unless an environment PRINTER variable is defined, when
                 # that's used as a printer, and the argument is taken to be
                 # a macro. If no macro is specified, make a temp one
                 IF($?printer == 0) {
                    DEFINE printer ? { what kind of printer? }
                 }
                 del1
                 IF($?2 == 0) {          # only one arg
                    IF($?PRINTER == 0) { DEFINE PRINTER : }
                    IF($?PRINTER) {
                       DEFINE 2 $PRINTER
                    }
                 }
                 IF($?1) {
                    if($?2) {            # 2 args
                       DEFINE _mac $1
                       DEFINE _temp 0    # no temp macro
                    } ELSE {             # 1 arg, take as printer
                       DEFINE 2 $1       # printer
                       DEFINE _temp 1    # need temp macro
                    }
                 } ELSE {                # no $1
                    IF($?2 == 0) { DEFINE 2 " " }
                    DEFINE _temp 1       # need temp macro
                 }
                 IF($_temp) {
                    DEFINE _mac _mac
                    echo "Create temporary macro, exit with ^X"
                    MACRO EDIT $_mac
                    IF(is_set($_mac,1) == 0) {
                       DEFINE _mac DELETE DEFINE _temp DELETE 
                       DEFINE _test DELETE
                       RETURN
                    }
                 }
                 DEVICE $printer $2
                 $_mac \n DEVICE $device
                 IF($_temp) { MACRO $_mac DELETE }
                 DEFINE _mac DELETE DEFINE _temp DELETE bell
    load         # load macros in default directory
                 DEFINE macro :                   # get default directory
                 MACRO READ "$!macro"$1  # read macro file
                 IF($?mfiles == 0) {
                    DEFINE mfiles $1
                 } ELSE {
                    DEFINE 3 0
                    FOREACH 2 ( $mfiles ) {
                      IF('$2' == '$1') { DEFINE 3 1 }
                    }
                    IF($3 == 0) { DEFINE mfiles < $mfiles $1 > }
                 }
    load2 1      # load macros in (second) default directory
                 DEFINE macro2 : # get directory
                 IF($?macro2) {
                    MACRO READ "$!macro2"$1  # read macro file
                 } ELSE {
                    echo Directory macro2 is not defined
                 }
    logerr 3     # logerr x y error, where y is logged, and error isn't
                 SET _y = 10**$2
                 SET d_y = LG(_y + $3) - $2 ERRORBAR $1 $2 d_y 2
                 SET d_y = $2 - LG(_y - $3) ERRORBAR $1 $2 d_y 4
                 DELETE _y DELETE d_y
    lsq  15      # do a least squares fit to a set of vectors
                 # syntax: lsq x y [ x2 y2 [rms]] Fit line y2=$a*x2+$b to x y
                 # optionally, calculate rms residual as $rms
                 # see rxy to find product moment correlation coeff,
                 # and spear for Spearman's corr. coeff., and significance
                 SET _n = DIMEN($1)              # number of points
                 SET _sx = SUM($1)               # sigma x
                 SET _sy = SUM($2)               # sigma y
                 SET _sxy = SUM($1*$2)           # sigma xy
                 SET _sxx = SUM($1*$1)           # sigma xx
                 DEFINE a ( (_n*_sxy - _sx*_sy)/(_n*_sxx - _sx*_sx) )
                 DEFINE b ( (_sy - $a*_sx)/_n )
                 IF($?3 && $?4) {
                    SET $4=$a*$3+$b
                    IF($?5) {
                       DEFINE $5 ( sqrt(sum(($a*$1 + $b - $2)**2)/dimen($2)) ) 
                    }
                 }
                 FOREACH v ( _n _sx _sy _sxy _sxx ) { DELETE $v }
    playback     ## define "all" from buffer, and run it
                 # with args, only playback those lines
                 IF($?1 == 0) {
                    DEFINE 1 0 DEFINE 2 10000
                 } ELSE {
                    IF($?2 == 0) { DEFINE 2 $1 }
                 }
                 del1 MACRO all $1 $2 all
    read_old 1   del1 # read a Mongo file onto the history buffer
                 READ OLD temp $1
                 WRITE HISTORY temp MACRO temp { DELETE }
    rel 2        # Relocate, accepting expressions
                 define 1 ($1) define 2 ($2) relocate $1 $2
    reverse 1    # reverse the order of a vector
                 SET _i = DIMEN($1),1,-1 SORT < _i $1 > DELETE _i
    sav 1        # Save to a file $1, don't save from files `$mfiles'
                 _save $1
    _save 1      # Save to a file $1, don't save from files `$mfiles'
                 del1
                 FOREACH 2 ( $mfiles ) { MACRO DELETE "$!macro"$2 }
                 DEFINE 2 0 define 2 ? { save vectors? }
                 SAVE "$!1" 1 $2 1
                 FOREACH 2 ( $mfiles ) { MACRO READ "$!macro"$2 }
    


    Cumulate is given as a way not to write macros if you can
    help it (in this case, I couldn't). A better example is reverse
    which reverses the order of
    the elements in a vector without resorting to a DO loop.



    The macro da could have been defined to be DATA, but there
    are various special characters that appear in filenames;
    try data /usr/spool/junk or

    data disk$data:[ETHELRED]junk.dat. The macro da
    provides a set of double quotes to escape these unwanted interpretations.
    Incidently, da "/usr/spool/junk" won't work.



    DELETE HISTORY deletes the last command on the history buffer, so
    del1 alone on a line will delete itself, which can be used to
    prevent a command from appearing on the history
    list, for example changing devices with dev; dev also defines
    a variable device which is used by the hcopy and hmacro

    macros to make hardcopies, while returning you to your initial device. The
    startup macro listed above also sets device, if it is specified
    in your `.sm' file. You should be careful not to include more
    than one del1 macro in any macro that you write yourself, as
    each del1

    will remove a command from history and you could find commands mysteriously
    disappearing.



    Gauss evaluates a Gaussian, e.g. SET x=-3,3,0.05 SET g=gauss(x)
    lim x g box con x g
    , an example of using a macro like a function definition.
    (For this example to work, you have to define variables mean and
    sig first).


    There is an example of reading variables from files and using
    them in macro get. This reads a word from a line in a file with
    the DEFINE nn READ i j command, which sets $nn to be the
    jth word on
    line i of the current data file. This variable is then used to
    READ a
    vector, which is given the appropriate name. So if a file looks like:

    This is an example file
    alpha   beta    gamma   delta
    1       10      0.1     1e1
    2       20      0.2     1e2
    3       30      0.3     1e3
    4       40      0.4     1e4
    5       50      0.5     1e5
    


    then the commands

    GET 2 1   GET 2 2   GET 2 3   GET 2 4
    


    will read `1 2 3 4 5' into vector alpha, `10 20 30 40 50' into beta and so
    forth. Note that

    DEFINE READ file_id 1 LABEL $file_id
    


    will write out `This is an example file' to the current position of the
    plot pointer (see, e.g. RELOCATE). Incidently, READ ROW omega 5
    would set the vector omega to have values `3 30 0.3 1e3'.



    The macros hcopy and hmacro make hardcopies of, respectively,
    the playback buffer and a macro. Both assume that the variables

    device and printer are set. device is set from
    your `.sm' file and by the dev macro; printer is assumed
    set in `.sm'. (See `startup' file above). If all is well, the macros
    switch to device printer (with an argument to specify which
    sub-printer is desired. We have so many laser printers here...), execute
    the desired commands, and return to the initial device. When the

    printer device is closed, hardcopy will result. Note the use of
    \n to ensure that no nasty things happen;
    if there were no \n and the buffer ended with LABEL Hi, the
    plot could appear with a label Hi device tek4010.
    The versions of hcopy and hmacro given here
    accept a variable number of arguments (`13' means up to 3 arguments).
    The first (if present) is
    taken to be the desired laser printer(17),
    the next argument is the number
    of the first line that you want played back, and the third is the last
    line number. (If you omit both line numbers you'll get the whole
    buffer; if you omit the second you'll just get the one line).
    The macro sees what it has been given by using $? to see which
    variables are defined, and acts accordingly. hmacro is somewhat
    similar, except that if you omit an argument it is taken to be the
    macro name, and a temporary one is created for you.
    The playback macro deals
    with its arguments in a similar way, and is discussed further in the examples
    at the end of this section.



    load enables you to read a set of macros from a directory
    specified as macro in your environment file.
    Load2 is similar, but it looks in directory macro2. The macro
    unload (not listed here) will undefine the loaded macros.
    Note that a list of all the loaded macros is kept in $mlist, which is used by the sav macro to avoid SAVEing
    lots of system macros. sav is written in terms of a macro

    _save so that it won't itself be forgotten (by MACRO
    DELETE
    ) while in the middle of saving macros.



    If you want to put errorbars on logarithmic plots, logerr is the macro
    you've been looking for. It calculates the correct length for the errorbars,
    and plots them de-logging and re-logging as appropriate.



    The macros rel and dra illustrate a method of using expressions,
    rather than numbers, in the commands RELOCATE and DRAW. There
    are Good Reasons why DRAW won't accept an expression
    directly (see section The Command Interpreter).
    These macros exploit the fact that the arguments to a macro are whitespace
    delimited, so a string such as 1+2/$x comprises one argument.
    Redefining the arguments means that the macros don't have to define,
    and then delete, a couple of variables to hold the expressions.



    Now that you have had your appetite whetted, we strongly recommend
    that you take the time to look through the other macros that are
    available (see section The System Macro Libraries).
    Otherwise how would you know that there are macros to draw arrows on
    plots, do KS and Wilcoxon tests on vectors, and a host of other good
    things?

    More Examples of Macros





    In all these examples, we'll use the del1 macro discussed
    above to keep commands off the history list.
    Let's start with a Fourier series, to demonstrate SM's ability
    to manipulate vectors. All keywords are capitalised for clarity.
    Start SM, choose a plotting device (with
    the dev macro), and erase all the commands on the history (or
    playback) buffer with DELETE 0 10000. Then type the following
    commands:

    SET px=-PI/10,2*PI,PI/200
    SET y=SIN(px) + SIN(3*px)/3 + SIN(5*px)/5 + SIN(7*px)/7
    SET y=(y>0)?y:0
    LIMITS -1 7 y
    BOX
    CONNECT px y
    


    The vector px could just as well have been read from a file. You
    should now have a part of a square-wave, truncated at 0.



    Now consider a simpler way of doing the same thing. For the present, clear
    the history buffer again (DELETE 0 10000), and type:

    SET px=-PI/10,2*PI,PI/200
    SET y=SIN(px)
    DO i=1,3 {
       SET val = 2*$i + 1
       SET y = y + SIN(val*px)/val
    }
    DELETE val
    LIMITS -1 7 y
    BOX
    CONNECT px y
    


    Here we use a vector val to save a value, an equivalent (but
    slower) loop using SM variables would be

    DO i=1,3 {
       DEFINE val (2*$i + 1)
       DEFINE y = y + SIN($val*px)/$val
    }
    DEFINE val DELETE
    


    That is all very well if you only ever wanted to sum the first four terms of the
    series. Fortunately there is a way to change this, using the macro editor. First
    define a macro consisting of all the commands on the history list:

    del1 MACRO all 0 10000
    


    will define the macro all to be history lines 0-10000.
    (You need the del1 to avoid having the MACRO all 0 10000 in
    your macro).
    Then you can edit it using

    del1 MACRO EDIT all
    


    when you have made the desired changes (e.g. changing DO i=1,3
    to DO i=1,20) use control-X to leave the editor and return to the
    command editor. Now you could type all to run your new macro,
    or put it back onto the history list. To do the latter, delete the
    commands now on the history list (the now-familiar DELETE 0 10000),
    then del1 WRITE HISTORY all to put the macro all onto the
    list. Now the

    playback command will run all those commands, and produce a better
    squarewave. (As discussed in a moment, playback is a macro so type it
    in lowercase, unless you have defined your own PLAYBACK macro.)



    This ability to edit the history buffer is convenient, and there is a macro
    provided called edit_hist which goes through exactly the steps that we
    took you through. The trick of including a del1 in macros is
    pretty common, for example h is defined as

    del1 HELP so that it won't appear on the history list.
    The macro playback is rather similar to edit_hist, but instead
    of editing and then writing all, it executes it. We discussed
    the possibility of just playing back a limited number of lines while
    talking about hcopy, just say playback n1 n2.



    Now that you have a set of commands which produce a Fourier plot, it
    would be nice to define a macro to make plots, taking the number of
    terms as an argument, and then free the history buffer for other things.
    After a playback, the macro all is defined, so let's change its
    name to square. There is a macro ed defined more-or-less as

    del1 MACRO EDIT, so type ed all to enter the macro editor.
    Use
    or control-P to get to line 0 and
    change the number of arguments from 0 to 1, and the name of the macro
    from all to square (the space between the name and the : is
    required.) Then go to the DO i=1,20 line, and change 20 to

    $1. Exit with control-X, clear the screen with era and
    type square 10. Now how do you
    save your nice macro? WRITE MACRO square filename will write it
    to file `filename', and next time you run SM
    MACRO READ filename
    will define it. In fact there is a command SAVE to save everything
    which can be a mindless way of proceeding.
    A macro similar to this Fourier macro called square

    is in the file demos in the default macro directory (and was used to
    produce the top left box of the cover to this manual). To try it yourself, type
    something like load demos square 20. (20 is the number of
    terms to sum.)



    If your wondering why ed is only `more-or-less' defined as del1 MACRO EDIT, it's because the real ed checks to see if you
    have provided a macro name, and if you haven't it edits the same macro
    as last time.



    But enough of macros which fiddle with the history buffer. Here are four
    sets of macros which do useful things, and may give some idea of the power
    available.
    First a macro to use the values of a third vector to mark points, then one
    to do least-squares fits to data points, then a macro to join
    pairs of points, and finally some macros to handle histograms and Gaussians.
    These macros are given in the format that SM would
    write them to disk (ready for a MACRO READ), with the name, then the
    number of arguments if greater than 0, then the body of the macro.



    First the points.

    alpha_poi 3   # alpha_poi x y z. Like poi x y, with z as labels for points
                  DO i=0,DIMEN($1)-1 {
                     DEFINE _x ($1[$i]) DEFINE _y ($2[$i])
                     RELOCATE $_x $_y
                     DEFINE _z ($3[$i])
                     PUTLABEL 5 $_z
                  }
                  FOREACH v (_x _y _z) { DEFINE $v DELETE }
    


    Here we use the temporary variables _x _y _z to get around
    restrictions on expressions in RELOCATE commands.
    Note the DO loop running from 0 to DIMEN($1)-1, produced
    by array indices starting at 0 not 1.
    If you wanted to use character strings as labels, this could be done by
    using the DEFINE READ command, but this would be a good deal slower as
    SM would have to rescan the file for each data-point. The top right
    box of this manual's cover was made using this macro.
    The use of alpha_poi (and also the macro file called ascii)
    has been superseded by the introduction of string-valued vectors into
    SM. Nowadays you'd simple read the column that you want to
    label the point with as a string (e.g. READ lab 3.s), set the
    point type to that string (e.g. PTYPE lab), and plot the points as usual
    (e.g. POINTS x y).



    The least-squares macro makes heavy use of the SUM operator.
    It could be used to find the dimension of a
    vector too, but only clumsily, and DIMEN is provided anyway. The macro
    is:

    lsq 4         # Do a least squares fit to a set of vectors
                  # Syntax: lsq x y x2 y2   Fit line y2=$a*x2+$b to x y
                  DEFINE _n (DIMEN($1))           # number of points
                  DEFINE _sx (SUM($1))            # Sigma x
                  DEFINE _sy (SUM($2))            # Sigma y
                  DEFINE _sxy (SUM($1*$2))        # Sigma xy
                  DEFINE _sxx (SUM($1*$1))        # Sigma xx
                  DEFINE a (($_n*$_sxy - $_sx*$_sy)/($_n*$_sxx - $_sx*$_sx))
                  DEFINE b (($_sy - $a*$_sx)/$_n)
                  SET $4=$a*$3+$b
                  FOREACH v ( _n _sx _sy _sxy _sxx ) {DEFINE $v DELETE }
    


    This does a linear fit, leaving the coefficients in $a and $b. It could
    be easily generalised to deal with weights, fits constrained to pass
    through the origin, quadratics...



    Our third example connects pairs of points. This was written to deal with
    a set of data points before and after a certain correction had been applied.

    pairs 4       # pairs x1 y1 x2 y2. Connect (x1,y1) to (x2,y2)
                  DO i=0,DIMEN($1)-1 {
                     DEFINE _x ($1[$i]) DEFINE _y ($2[$i])
                     RELOCATE $_x $_y
                     DEFINE _x ($3[$i]) DEFINE _y ($4[$i])
                     DRAW $_x $_y
                  }
                  FOREACH v ( _x _y ) { DEFINE $v DELETE }
    


    After the introduction of vectors for ANGLE and EXPAND
    (in version 2.1) this macro can be rewritten to be much faster:

    pairs    4    # pairs x1 y1 x2 y2. connect (x1,y1) to (x2,y2)
                  DEFINE 6 { ptype angle expand aspect }
                  FOREACH 5 { $!!6 } { DEFINE $5 | }
                  FOREACH 5 {fx1 fx2 fy1 fy2 gx1 gx2 gy1 gy2} {
                     DEFINE $5 DELETE
                  }
                  ASPECT 1
                  SET _dx$0=($3 - $1)*($gx2 - $gx1)/($fx2 - $fx1)
                  SET _dy$0=($4 - $2)*($gy2 - $gy1)/($fy2 - $fy1)
                  PTYPE 2 0
                  SET _a$0=(_dx$0 == 0 ? (_dy$0 > 0 ? PI/2 : -PI/2) : \
                      (_dy$0 > 0 ? ATAN(_dy$0/_dx$0) : ATAN(_dy$0/_dx$0) + PI))
                  ANGLE 180/pi*_a$0
                  EXPAND SQRT(1e-5 + _dx$0**2 + _dy$0**2)/(2*128)
                  POINTS (($1 + $3)/2) (($2 + $4)/2)
                  FOREACH 5 { $!!6 } { $5 $$5 DEFINE $5 DELETE }
                  FOREACH 5 ( _a _dx _dy ) { DELETE $5$0 }
    
    


    Note how DEFINE name | is used to save things like the angle
    and expansion, while DEFINE name DELETE is used to ensure that the
    up-to-date versions of things like fx1 are used (i.e. that they
    haven't been DEFINEd with a !).
    The name of the macro ($0) is used to
    make unique vector names, or at least names like _dxpairs that
    are very unlikely to be in use.



    SM allows you to plot a pair of vectors as
    a histogram, but what if you have only got the raw data points, not yet
    binned together? Fortunately, SM can do this
    binning for you. Consider the following macro:

    get_hist 6    # get_hist input output-x output-y base top width
                  # given $1, get a histogram in $3, with the centres of the
                  # bins in $2. Bins go from $4 to $5, with width $6.
                  SET $2 = $4+$6/2,$5+$6/2,$6
                  SET HELP $2 X-vector for $3
                  SET $3=0*$2 SET HELP $3 Histogram from $1, base $4 width $5
                  DO i=0,DIMEN($1)-1 {
                     DEFINE j ( ($1[$i] - $4)/$6 )
                     SET $3[$j] = $3[$j] + 1
                  }
                  DEFINE j DELETE
    


    Since this was written, a new feature was added to SM, the

    expression HISTOGRAM(x:y), to make histograms. The macro we discussed
    above can now be written much more efficiently as:

    get_hist 6    # get_hist input output-x output-y base top width
                  # given $1, get a histogram in $3, with the centres of the
                  # bins in $2. Bins go from $4 to $5, with width $6.
                  SET $2 = $4+$6/2,$5+$6/2,$6
                  SET HELP $2 X-vector for $3
                  SET $3=HISTOGRAM($1:$3)
                  SET HELP $3 Histogram from $1, base $4 width $5
    


    Suppose that your data is in vector x, for want of a better name, and
    it has values between 0 and 20. Then the command

    get_hist x xx yy 0 20 1
    


    will produce a histogram in yy, bin centres in xx, running
    from 0 to 20 with bins 1 unit wide. So you could plot it with
    lim xx yy box hi xx yy , and maybe it looks like a Gaussian. So what
    is the mean and standard deviation? The command

    stats x mean sig kurt echo $mean $sig $kurt
    


    will answer that, and find the kurtosis too. (Macro stats
    consists of lines
    such as define $2 ( sum($1)/dimen($1) ) ). Then we could use
    the macro gauss to plot the corresponding Gaussian,

    set z=0,20,.1 set gg=gauss(z) set gg=gg*dimen(x) con z gg
    


    The bottom left box of the cover was made this way. What if you don't
    like the way that the histogram looks? Try the macro barhist.
    Now, if you wanted to plot a lognormal, you'd have to write your own
    macro, and you could use SORT to find medians and add another macro
    to utils, followed by one to find Wilcoxon statistics...
    (Since this was written a wilcoxon macro was donated to stats).

    What Quotes What When


    This chapter is not really needed as all of its contents can be found
    elsewhere in this manual, but as people manage to become confused anyway,
    here's a summary. There are three ways in which characters can
    alter SM's behaviour:
    they can affect the way that characters and keywords are interpreted,
    they can be special to the grammar, and they can perform both functions.
    If you are confused, you might find a verbosity of four or five helpful.


    "..."

    Turn off the expansion of variables, the significance of mathematical
    operators such as / or :, and the recognition of keywords.
    For example, after DEFINE rhl
    Patricia
    , /data/$rhl

    would be interpreted as four tokens (/, data, /, and
    Patricia), while "/data/$rhl" is only one (/data/$rhl).
    Note that in the former case, the data will be taken to be part of
    a DATA command, and may well lead to a syntax error.
    If you need to force a variable to be expanded within double quotes, use
    an exclamation mark: "$!rhl". Double quotes have no syntactical
    significance.

    Incidently, "12" is a number as the closing " is
    read before the characters 12 are parsed. You need to say

    "12 " to make 12 a word; in a different package you
    might call that a bug.

    '...'

    Single quotes surround strings which may contain white space (spaces or tabs),
    characters such as + or /, or keywords.
    They don't affect variable expansion, so you have
    to enclose them in double quotes if you want to protect them. Of course, you
    must make sure that you are not quoting the single quotes -- use
    '"$abcd"' rather than "'$abcd'" .
    Strings are significant to the grammar so only use single quotes where they are
    needed. For example DATA 'my_file' is a syntax error, and

    SET s='abc' and SET s=abc mean quite different things.

    {...}

    Turn off all interpretation of special characters and keywords,
    just like double quotes.
    In fact, braces even turn off the expansion of $!var, to expand
    a variable within braces you need to say $!!var but you only very
    seldom need this. Braces have syntactical significance, delimiting lists.
    Wherever you can use braces you can use angle brackets.

    <...>


    Almost identical to {...}, but don't turn off variable expansions.
    In fact, <> don't always turn off keyword interpretation --
    specifically they only do so in str_list's (if you want to
    know what this means you'll have to read SM's grammar in file
    `control.y'). In practice you'll probably only meet this if you
    try saying Foreach f < quit when ahead > { echo $f }.

    (...)

    Parentheses don't turn off any sort of expansion, but can have
    syntactical significance.
    You are most likely to see this in DEFINE var ( 1 + 2 ) where the
    parentheses tell SM to evaluate the expression before defining the variable
    var as 3. Note that DEFINE var < 1 + 2 > defines
    var as 1 + 2 .

    $name

    Expand name as a variable. Expansion is turned off within single and
    double quotes and within braces. Because the expansion happens before
    the parser sees the input, variables cannot have any syntactical significance
    as the parser never knows about them. This means that variables could
    be used to make SM look like something quite different;
    for example after DEFINE begin "{ " DEFINE end "} ", you can say

    MACRO hi $begin echo Hello World $!!end
    

    (This is a little tricky. The spaces in DEFINE begin "{ " are
    needed so that SM is still in quote mode when it processes the {. You
    can probably figure out why I need to say $!!end -- the !! should
    be a Helpful Hint.)

    $(expr)

    Evaluate the expression expr and substitute the resulting value. This
    is identical to DEFINE temp ( expr ) $temp, but much more convenient.


    As a reasonably complex example, try to guess the output from:

    DEFINE hi {<"$!('Hello')" World>} DEFINE hello $hi echo :$hi:$hello:
    
    


    If you are not sure, try it
    (you might find VERBOSE 5 helpful)(18).

    Generating SM interfaces from e.g. python


    SWIG (the Simplified Wrapper and Interface Generator; see http://www.swig.org/)
    is a utility that allows you to use a pre-existing library as an extension to a
    scripting language such as python or perl5. SM now supports python; with a modicum
    of effort it could be used with perl (or ruby or ...). To use this feature,
    simply select a language when you run set_opts. You'll need to have swig

    installed (yes; set_opts checks), and maybe also some additional packages.



    To try this out, say (with the python port) python, and then

    import sm
    sm.demo('x11')
    

    Python


    To use SM with python, you must have the numpy package installed. After
    installing SM, you'll have to add your destination library (e.g. /usr/local/lib)
    to your PYTHONPATH.

    Reserved Keywords



    Keywords are reserved, so don't try to use them as macro names or
    whatever. You can use the lowercase forms if you explicitly ask to be
    allowed to overload them.
    The control words are :

    WORD STRING FLOAT INTEGER ( ) { } \n ! APROPOS BREAK CHDIR DEFINE DELETE DO
    EDIT ELSE FOREACH HELP HISTORY IF KEY LIST LOCAL MACRO OLD OVERLOAD PRINT
    PROMPT QUIT READ RESTORE RETURN ROW SAVE SET STANDARD TABLE TERMTYPE USER
    VERBOSE WHILE WRITE
    


    Arithmetic words are :

    ABS ACOS ASIN ATAN ATAN2 CONCAT COS DIMEN EXP FFT INT LG LN PI RANDOM
    SIN SQRT STRLEN SUM TAN WHATIS POWER_SYMBOL [ ] = + - * ** / < > | & ? :
    
    


    SM plotting keywords are:

    ANGLE ASPECT AXIS BOX CONNECT CONTOUR CTYPE CURSOR DATA DEVICE DOT DRAW
    ERASE ERRORBAR EXPAND FORMAT GRID HISTOGRAM IMAGE LABEL LEVELS LIMITS
    LINES LOCATION LTYPE LWEIGHT MINMAX NOTATION POINTS PTYPE PUTLABEL RANGE
    RELOCATE SHADE SORT SPLINE TICKSIZE WHATIS WINDOW XLABEL YLABEL
    


    With the exception of POWER_SYMBOL (which is equivalent to **)
    these are described below, with the convention that arguments between
    square brackets are optional. This has nothing to do with their use in
    subscripting arrays!

    Glossary of Terms used in this Manual




    .sm

    See Environment File.

    Environment File

    When you start SM it looks in a file
    (by default called `.sm') to discover where to find files that it
    needs (such as the default macros, the help files, and the font files).
    You can access variables stored in the environment file yourself,
    although this is probably seldom done by non-gurus. For more details,
    see section Environment Variables.

    Expression

    An SM expression is something that can appear on the right hand side of
    a SET command. More specifically, it is something that can appear
    as part of the right hand side of a SET command (this
    excludes implied do loops: SET x=1,10,2). Expressions may also
    appear in other contexts, such as in the ANGLE command, or in

    DEFINE name ( expression ). A formal definition of an
    expression is given by the YACC grammar in `control.y' as the
    non-terminal symbol expr.

    Filecap

    Binary files produced by different programmes (and
    languages, and even compilers) are not identical, Fortran
    `unformatted' files being a glaring example. A filecap file is a
    database used to describe the byte-by-byte format of binary files, to
    allow SM to read them (using the IMAGE command).

    Graphcap

    There are a very large range of graphics terminals
    (and laser printers and so forth) in this world, and each seems to
    have its own set of commands. A graphcap
    file is a database that is able to describe (almost) all of these
    dialects, allowing SM to plot on a wide range of devices

    History

    SM remembers commands as you type them, so that you
    can repeat them or modify them (which includes correcting mistakes).
    The set of remembered commands is referred to as the history buffer.

    List

    The word list is used in a few places in the manual
    in the specific sense defined by the YACC grammar in `control.y'. A
    list is simply a list of words or numbers, and its meaning depends on
    the context. For example, SET x=3*{1 2 3} will set the vector

    x to be 2 4 6, while MACRO hi { echo Hello} will
    define the macro hi.

    Macro

    A macro is an abbreviation for a set of commands, so
    instead of typing a complicated sequence of commands you can simply
    type the macro's name. You can either think of macros as a new commands in
    their own right or as subroutines.

    Mongo

    Mongo is a plotting package written by John Tonry, and
    widely used in astronomy
    departments. SM's command language was based on Mongo's, and we have
    provided some support for an easy transition from Mongo to SM.

    p_expr

    A parenthesised expression. Many commands expect to be passed the name of
    a vector, but will accept an expression in parentheses; for example
    in the command POINTS x (y + 2/z), (y + 2/z) is a p_expr.

    s_expr

    A scalar expression. This is a term used in some of the command descriptions;
    examples would be 210157, x[12], or x. In the latter
    case, the first element of the vector x would be used, so it is
    equivalent to x[0].

    Stdgraph

    SM uses the stdgraph device driver for most devices, using the information
    in the graphcap file (see section The Stdgraph Graphics Kernel).

    String

    A string to SM is a sequence of characters enclosed in single quotes:
    'This is a string'. Strings are primarily used in vector expressions,
    but are also used in a few other places (e.g. to specify a format for a
    PRINT or READ command). Note that characters in double quotes
    are not strings to SM, merely characters protected from variable
    expansion.

    Termcap

    Terminals come in many, many, flavours and types.
    Their peculiarities are described by a termcap file, allowing
    SM's command editor to run on (almost) any terminal.

    TeX

    TeX is a typesetting language developed by
    Donald Knuth. We provide an emulation of certain parts of TeX's
    mathematics mode in SM's label commands.

    Overload

    A keyword (such as DEFINE or SET) is said
    to be overloaded if its meaning has been changed. Usually this
    will be by adding functionality, rather than by actually changing what
    it does.

    Variable

    A variable is an abbreviation for a sequence of characters, and may
    appear anywhere that the characters in question could appear. Even if the
    variable contains a number (e.g. 6.62559e-34) it is still just
    a characters, although SM may choose to treat them as a number in
    some contexts (e.g. the right-hand side of a SET command).

    Vector

    A set of one (actually, zero) or more elements. The
    elements can be either numerical (floating point) or strings. Vectors
    are SM's primary data type. Do not confuse a 1-element vector (a scalar)
    with a variable (see section String Variables).

    YACC


    The SM command language is written in a language called
    YACC (which is supported on Unix systems). We have provided an
    implementation of YACC called Bison in the SM distribution.

    Command Reference


    This is the reference manual to SM's commands


    • Abort: Abort the current plot without producing a hardcopy
    • And: Logical AND with short-circuiting

  • Angle: Draw Points and Text at an Angle
  • Apropos: List all Commands and Macros Matching a String
  • Arithmetic: Arithmetical Operations
  • Aspect: Print or Set the Plot's Aspect Ratio
  • Axis: How to Draw a Single Axis (see also Box)
  • Box: Draw a Box around a Graph
  • Break: Break out of a While loop
  • Chdir: Change Directories
  • Connect: Connect a Set of Points
  • Contour: Contour an IMAGE
  • Ctype: Set the Colour of Lines
  • Cursor: Display a Cursor
  • Data: Specify the Data File to Use
  • Define: Define a Variable
  • Delete: Delete Something
  • Device: Chose an Output Device
  • Dither: Floyd-Steinberg Dither an Image
  • Do: Do-Loops
  • Dot: Draw a Dot of the Current Type
  • Draw: Draw a Line to the Current Plot Position
  • Edit: Change Key Bindings for the Editor
  • Environment Variables: Variables Effecting SM's Behaviour
  • Erase: Clear the Screen
  • Errorbar: Draw Errorbars
  • Expand: Change the Size of Points and Text
  • Fft: Fourier Transform a Vector
  • Foreach: Do Something to each Member of a List
  • Format: Specify the Axis Label Format
  • Grid: Draw a Grid at the Axis Ticks
  • Help: Help Me Please
  • Histogram: Draw a Histogram
  • History: List the Commands that you have Executed
  • Identification: Write an I/D string on your Plot
  • If: Do Something If an Expression is True
  • Image: Read a Binary Image
  • Key: Define a Key to Execute a Command
  • Label: Draw a Label on a Plot
  • Levels: Specify the Levels for a Contour Plot
  • Limits: Set the Axis Limits
  • Lines: Set which Lines of a File should be Read
  • List: List Something; Macros, Variables, Vectors, ...
  • Local: Make a Variable or Vector Local to a Macro
  • Location: Specify where on the Screen the Plot Should Appear
  • Logical: The Possible Logical Operators
  • Ltype: Set the Pattern Used to Draw Lines
  • Lweight: Set the Width of Lines
  • Macro: Define a Macro, or Read or Write a Macro File
  • Meta: SM's Support for Metafiles
  • Minmax: Find the Minimum and Maximum of an Image
  • Notation: Chose between Fixed and Exponential Axis Labels
  • Or: Logical OR with short-circuiting
  • Overload: Change the Meaning of a Keyword
  • Page: Start a New Page
  • Points: Draw some Points
  • Print: Print some Vectors
  • Prompt: Set the Prompt
  • Ptype: Choose the Type of Markers for Points
  • Putlabel: Draw a Label on the Plot
  • Quit: Leave SM
  • Range: Specify a Range for the Axes
  • Read: Read Vectors from a File
  • Relocate: Move the Current Plot Pointer
  • Restore: Restore a SAVEd SM Environment
  • Return: Return from the Current Macro
  • Save: SAVE your SM Environment
  • Set: Set a Vector to an Expression
  • Shade: Shade a Region of a Plot
  • Show: Print the Value of Various Quantities
  • Sort: Sort a Number of Vectors
  • Spline: Fit a Cubic Spline to Two Vectors
  • Strings: String Operations
  • Surface: Draw a Surface from an Image, with Hidden Line Removal
  • Table: Read from tables
  • Termtype: Set the Terminal Type
  • Ticksize: Specify the Style of Axis Ticks
  • User: A User-Provided Command
  • Verbose: Adjust SM's Chattiness
  • Version: What version of SM are you Running?
  • Viewpoint: Choose the Direction used to View Surfaces
  • Whatis: Find the Type of a String
  • While: Repeat Commands while an Expression is True
  • Window: Choose a Plot Window; Use just Part of the Device
  • Write: Write a String to a File
  • Xlabel: Draw an X-axis Label
  • Ylabel: Draw an Y-axis Label

  • Abort

    Syntax: ABORT
    





    ABORT closes the current device without producing any hardcopy. If you
    are writing an output file it will be removed. You are left talking to
    the null device, so you probably want to follow ABORT with a DEVICE
    command.


    And

    Syntax: AND
    




    In a scalar context, you can use AND instead of &&. The difference
    is that AND doesn't evaluate the right-hand-side of the expression if
    the left-hand-side is false; See section If, for examples.



    Angle


    Syntax: ANGLE expr
    


    For most purposes only the first element of the expr is used, let's
    call it D as it's an angle in degrees.



    ANGLE will cause text from LABEL to come out D degrees
    anti-clockwise from horizontal. It also causes points to be rotated
    counter-clockwise by D degrees.


    If D is non-zero it will force axis and other labels to be
    written with SM's internal fonts, and will overrule the
    tendency to put x-axis labels horizontal, and y-axis labels vertical.



    For plotting points the full vector of values is used, with the
    point rotated by the value of expr. If more points are specified than
    the dimension of expr, the first element will be used for the excess.



    The current value of ANGLE is (almost) always available as the variable
    $angle (it is one of the special variables that are affected by the

    DEFINE variable | command).



    Apropos

    Syntax: APROPOS pattern
    





    Apropos lists all macros whose name or introductory comments match
    the given pattern. Probably the most common use for the command is
    simply to look for a word -- e.g. APROPOS histogram.



    If your system supports it, APROPOS will also search the help files
    for the given pattern (in this case matches may not extend over more
    than one line). If VERBOSE is zero only the line containing the
    match is printed; if VERBOSE is one or more then a couple of
    lines on each side of the match are printed too. If the pattern
    matches more than once each match will be printed, merged together if
    appropriate and separated by line of dashes otherwise. If you use `q'
    to stop looking at the help files APROPOS will immediately proceed to
    search the macros.



    The pattern is a slightly restricted version of a
    normal Unix regular expression, specifically:

    .

    Matches any character except \n.
    [...]

    Matches any of the characters listed in the [ ].

    If the first character is a ^ it means use anything except
    the range specified (in any other position ^ isn't special)

    A range may be specified with a - (e.g. [0-9]), and if a ]
    is to be part of the range, it must appear first (or after
    the leading ^, if specified). A - may appear as
    the special range ---.

    ^

    Matches only at the start of the string. Note that you must quote
    the ^ with an ESQ-q if you use it as your history
    character -- look in the index under history to learn how
    to change it.

    $

    Matches only at the end of a string.

    \t

    Tab

    \n

    Newline

    \.

    (any other character) simply escapes the character (e.g. \^)

    *

    Any number of the preceding character (or range)

    ?

    One or more of the preceding character or range


    By default searches are case insensitive, but you can make searching
    sensitive to case by deleting the variable case_fold_search (you can do this
    by putting a line case_fold_search 0 in your `.sm' file if you
    so desire).



    The name and the comments are searched separately, so you could list
    all macros beginning with a, b, c, d, e, or z by saying

    APROPOS ^[a-ez]
    


    (which works because all comments start with a #),
    or

    APROPOS "^#[^#]"
    


    to list all macros that start with a single # (the quotes are
    needed to stop the #'s from being treated as comment characters).



    Aspect

    Syntax: ASPECT A
    






    Set the aspect ratio (Y/X) to be A; This is used in drawing
    characters and points and is reset when a new DEVICE command is issued.


    The current values of the x- and y- dimensions of the current device are
    (almost) always available as the variables
    $nx and $ny, and the current aspect ratio is $aspect
    (they are some of the special variables that are
    affected by the DEFINE variable | command).




    If A is exactly 0, the current aspect ratio is printed -- this is equivalent
    to echo $aspect and is retained as a curiosity.



    Usually the aspect ratio is calculated by SM to make
    characters look right (and to make square points square), but it is
    sometimes useful to override this, especially when positioning labels
    on graphs that will be plotted on printers of different aspect ratios.



    It might be worth going through an example. Suppose that you want to make
    a plot that really is square when printed; how should you proceed?



    The available plotting area runs from 0--32767 on each axis. So a plot
    set up as

    
    location 5000 20000 5000 20000
    


    will have the same aspect ratio as the plotting device, in general rectangular.
    We can write this as

    define len 15000                # axis length, SCREEN units
    location 5000 $(5000 + $len) 5000 $(5000 + $len)
    


    if we feel sophisticated.



    The variable $aspect tells you the Y/X ratio of the current device;
    so the location

    location 5000 $(5000+$len) 5000 $(5000+int($len/$aspect)) box
    


    will be a square box. Of course, you'd probably really want to say

    if($aspect > 1) {
       location 5000 $(5000+int($aspect*$len)) 5000 $(5000+$len) box
    } else {
       location 5000 $(5000+$len) 5000 $(5000+int($len/$aspect)) box
    }
    



    There is a problem with this; the sizes of points and labels are varied to
    look right with the current aspect ratio. This means that a

    putlabel 5 Hello World
    


    command that looks fine on the screen of your workstation will look awful
    on the printer. That's where the ASPECT command comes into play: on your
    workstation lie to SM and tell it that the aspect ratio is that of the
    printer. How do you do that? Well, the slick way is to say

    macro aspect_as_device 1 {
       DEVICE $1
       define 1 $aspect
       ABORT
       DEVICE $device
       ASPECT $1
    }
    


    which assumes that you use a version of the device command that saves the
    current device as $device; the macro dev does this, and you can
    overload device to mean dev. Then you can say

    aspect_as_device postport
    


    to force the same aspect ratio as the postport device.; your plots
    will look ugly on the screen but beautiful when printed.



    Arithmetic

    Arithmetic
    


























    Arithmetic is allowed on vectors and scalars in SM, using the following
    operators, where expr is a expression, s_expr is a scalar expression (e.g.
    a number), and vector the name of a vector.

    Nonary (?):
    
    PI              Pi
    


    Unary:
    
    -expr           Change sign             ABS(expr)       Absolute value
    ACOS(expr)      Arccosine               ASIN(expr)      Arcsine
    ATAN(expr)      Arctangent              COS(expr)       Cosine
    CTYPE()         Return CTYPEs           DIMEN(vector)   Dimension of a vector
    EXP(expr)       Exponential             FLOAT(expr)     Convert to float
    GAMMA(expr,expr) Incomplete gamma fn    INT(expr)       Integral part
    LG(expr)        Log_10                  LN(expr)        Log_e
    RANDOM(s_expr)  Random numbers          SIN(expr)       Sine
    SORT(expr)      Sort                    SQRT(expr)      Square root
    STRING(expr)    Convert to a string     SUM(expr)       Sum_i expr_i
    TAN(expr)       Tangent                 VECTOR[expr]    Elements of an array
    { list }	Set vector to list      < list >	Set vector to list
    ( expr )        Raise precedence
    
    
    Binary:
    
    expr + expr          Add                expr - expr     Subtract
    expr CONCAT expr     Concatenate        expr * expr     Multiply
    expr / expr          Divide             expr ** expr    Exponentiate
    expr & expr          Bitwise AND        expr | expr     Bitwise OR
    expr << expr         Bitshift left      expr >> expr    Bitshift right
    expr % expr          Modulus            ATAN2(expr_y,expr_x) Atan2
    
    


    (note that a bitwise XOR may be achieved as | - &).



    There are also some special operators:

    HISTOGRAM(expr:expr)            Construct histogram
    IMAGE(expr,expr)                Extract cross section (x, y coordinates)
    IMAGE[expr,expr]                Extract cross section (x, y indices)
    expr1 ? expr2 : expr3           expr2 if expr1 is true, else expr3
    DO(s_expr, s_expr)              Implicit DO loop
    DO(s_expr, s_expr, s_expr)      Implicit DO loop with increment
    


    GAMMA returns an incomplete Gamma function, so GAMMA(a,infty) = 1.



    RANDOM generates a vector of s_expr random numbers in the
    range [0,1]. If you don't specify a seed (using SET RANDOM) one
    will be chosen for you based on the current time.



    ATAN2 is the same as C's function of the same name, and is
    equivalent to ATAN(y/x). It gives a result in the range

    -pi -- pi dealing correctly with divisions by zero.



    CTYPE returns a vector of red + 256*green + 256^2*blue, giving the
    currently defined colours; CTYPE(STRING) returns their names
    (see section Strings).



    DO generates a range of values, e.g. set x=do(1,5) sets
    x to have the values 1 2 3 4 5; this is the same as

    set x=1,5; but set y=100 + sin(pi*do(0,10)/10) is more
    interesting. You can specify an increment, so do(5,1,-1) is
    5 4 3 2 1.



    The expression
    VECTOR[expr] results in a vector of the same dimension as
    the expr, with elements taken from VECTOR

    (i.e. VECTOR[INT(expr_i)]). See, for example, the macro interp.

    You can also use WORD([ expr [ , ... ]]) as part of
    an expression, where WORD is a macro taking zero or more arguments.



    The precedences are what you'd expect, with ** being highest, then
    *, / and %, then + and -, then
    CONCAT, then the bitwise and logical operators, and finally

    ?: has the lowest priority of all. You should not assume any
    precedence between logical and bitwise operators, because if you do you'll
    be fooled (e.g. 1||0 | 0x6 is 7, but 0x6 | 1||0 is 1);
    if you use parentheses all will be well
    (1||(0 | 0x6) is 1 and 0x6 | (1||0) is 7).

    If you have defined an image file with the IMAGE command,

    IMAGE(expr,expr) is an expression to extract values from your image.
    The two expressions give the x and y values where the image is to be sampled.
    For example SET x=0,1,.01 SET z=IMAGE(x,0.5) will extract a horizontal
    cross section through an image. As an alternative, you can use (0-based)
    indices to extract the values with IMAGE[expr,expr]; there are
    examples under IMAGE (see section Image).

    HISTOGRAM(expr1:expr2) constructs a histogram from a vector,
    where the data is in expr1, and expr2 (which must be sorted)
    gives the location of the bins.
    If the values of expr2 are equally spaced, the `location' of the bin
    means the centre; if they are not, a bin is defined by saying that points with
    value (e2[i-1] + e2[i])/2 <= x < (e2[i] + e2[i+1])/2 go into the

    ith bin.
    Note that values on bin boundaries go into the higher bin.




    a ? b : c is very useful if you want to treat some value of an
    expression specially. You could do this with a loop but ?: is
    much faster; for example

    set y = lg(x > 0 ? x : 1e-37)
    set y = sqrt(x >=0 ? x : 0)
    
    


    Due to the way that SM evaluates these expressions you may see warnings from
    the parts of the expressions that are not used (i.e. where the logical
    expression is false). You can turn down the verbosity, of course, or you
    could try sending mail us mail to see if we can't fix it (but it isn't easy,
    or else we'd have done it already).



    See `Logical' for the logical operators, `Strings' for string operators,
    and `whatis' for finding out if strings are numbers, words, vectors, or
    whatever.


    Axis

    Syntax: AXIS A1 A2 VSMALL VBIG AX AY ALEN ILABEL ICLOCK
            AXIS A1 A2 VSMALL VBIG VLAB AX AY ALEN ILABEL ICLOCK
            AXIS A1 A2 ASMALL ABIG AX AY ALEN ILABEL ICLOCK
    




    Makes an axis labeled from A1 to A2 at location AX,
    AY, length ALEN.
    The first form (with VSMALL and VBIG) specifies the values
    where you want small and big ticks explicitly; if you specify the string-valued
    vector VLAB it will be used to label the big ticks.
    The third form is more
    obscure: If ABIG > 0 use that for spacing of large ticks.
    If ASMALL < 0 make a logarithmic axis, if ASMALL = 0, do
    the default. (See TICKSIZE for more on the meaning of negative

    ASMALL and/or ABIG).
    If ASMALL > 0 try to use that for the spacing of small ticks.



    ILABEL is 0 for no labels, 1 for labels parallel to axis, 2 for
    perpendicular to axis, and 3 for neither labels nor ticks.
    ANGLE determines the angle of the axis.



    ICLOCK is used for (too) many purposes; it's treated as three
    integers of 1, 2, and 1 bits respectively.

    ICLOCK      & 0x1:      Control the ticks orientation:
                            0       Anticlockwise from the axis
                            1       Clockwise from the axis
    (ICLOCK>>1) & 0x3:      Control the tick direction:
                            0       Ticks are perpendicular to axis
                            1       Ticks are vertical
                            2       Ticks are vertical
                            3       Don't draw any ticks
    (ICLOCK>>3) & 0x1:      Control which side of the axis the ticks appear:
                            0       The same size as the labels
                            1       The opposite side to the labels
    



    If you prefer not to think in terms of bitwise operators, this can be
    written as if ICLOCK is even the ticks are anticlockwise on the
    axis, if odd they are clockwise. You usually want the ticks
    perpendicular to the axes, and this is what you get with ICLOCK 0
    or 1; if it is 2 or 3 the ticks are vertical, and if 4 or 5 they are
    horizontal. The labels are on the opposite side of the axis from the
    ticks unless you add 8 to the numbers given above.



    For example, the following commands are equivalent to BOX:

    
    ANGLE 0
    AXIS $fx1 $fx2 0 0 $gx1 $gy1 $($gx2-$gx1) 1 $(0|8)
    AXIS $fx1 $fx2 0 0 $gx1 $gy2 $($gx2-$gx1) 0 $(1|8)
    ANGLE 90
    AXIS $fy1 $fy2 0 0 $gx1 $gy1 $($gy2-$gy1) 2 $(1|8)
    AXIS $fy1 $fy2 0 0 $gx2 $gy1 $($gy2-$gy1) 0 $(0|8)
    ANGLE 0
    


    (except that I set ICLOCK's 0x8 bit to draw the ticks
    outside the box).



    If you want to label the bottom axis of some
    plot only at prime points try

    SET b={1 2 3 5 7 11 13 17 19} SET s=0,20
    AXIS 0 20 s b 3500 3500 27500 1 0
    


    If you have used LIMITS to scale the axes and LOCATION or WINDOW
    to move them, you could say something like

    AXIS $fx1 $fx2 s b $gx1 $gy1 $($gx2-$gx1) 1 0
    


    An example of using your own string valued labels would be:

    set s=1,7,.5 set b=1,7 set labs={ O B A F G K M }
    LIMITS 1 7 0 0
    AXIS 0 10 s b labs 3500 3500 27500 1 0
    


    which works as expected. If you don't have a shift key and try using
    lower case (obafgkm) you'll be surprised as all the letters are not
    at the same level (as they don't all have the same height). The easiest way
    to deal with this is to make them all the same height:

    set labs={ o b a f g k m } + '\\strut'
    


    (a strut is a TeXism that has the height and depth of a parenthesis;
    I'm afraid that you do have to escape the \ in the string). If that leaves
    too much space try:

    set labs='\\move 100' + { o b a f g k m } + '\\strut'
    


    I think that you get the point.



    If you want more control over placement and sizes of axis labels and
    ticks, you can force SM to draw them separately:

            EXPAND 0.5
            AXIS $fx1 $fx2 0 0 $gx1 $gy1 $($gx2-$gx1) 0 $(1<<3)
            EXPAND 1.44
            AXIS $fx1 $fx2 0 0 $gx1 $gy1 $($gx2-$gx1) 1 $(3<<1)
    
    


    gives smaller-than-usual ticks outside the box with larger-than-usual labels
    (you could have used define default_font "2" to achieve the latter)



    The distance of labels from axes is controlled by the SM variable
    label_offset; increase it to move them further away.


    Rather than use AXIS to draw all of your axes, it may be easier
    to use BOX with some 3's to disable its axis-drawing habits. You'll
    still get a box, but no ticks or labels. For example,

    LIMITS 0 1 0 10 BOX 1 2 0 3 TICKSIZE 0 0 -1 0 BOX 3 3 1 3
    


    will label the y-axis with both linear and logarithmic axes.



    This was changed in V2.1: To specify logarithmic axes you should
    now specify the logarithms, just as you do to BOX.
    For example, to
    draw a logarithmic axis running from 1 to 1000,
    specify A1 as 0 and A2 as 3, rather than 1 and 1000.



    See NOTATION if you want to control the use of floating point
    or exponential notation.
    You can control the font used by setting
    the variable default_font.
    If you want your positive and negative exponents to line up
    define the SM variable line_up_exponents; if it's 1 they'll
    be padded with a space, if 2 or more, with a +
    (you can do this in your `.sm' file).



    Box

    Syntax: BOX [ INTEGER1 INTEGER2 [ INTEGER3 INTEGER4 ] ]
    





    BOX puts axes around the plot region, labelling the lower and left according
    to the values set by LIMITS and TICKSIZE.
    If arguments INTEGER1 and INTEGER2 are included (default 1 and 2)
    they are used as ILABEL

    arguments for the lower and left axes (see AXIS). An ILABEL of 0 means
    to omit axis labels, 1 produces labels parallel to the axis, 2 perpendicular,
    3 omits both labels and tickmarks, and 4 omits the axis entirely.
    INTEGER3 and
    INTEGER4 are
    used for the top and right axes.



    If you want to change the font used for axis labels, define the
    variable default_font, either interactively (DEFINE
    default_font oe
    ), or by putting a line in your `.sm' file:

    default_font oe. This affects regular as well as axis labels,
    and only works if you use TeX_strings, which we recommend
    anyway.



    See section Notation if you want to control the use of
    floating point or exponential notation, and some details on how to draw
    exponents. If you want more control over your axis labels, see section Axis.



    Break

    Syntax: Break
    



    Exit the current WHILE (see section While) loop, and continue executing
    commands after it.



    You cannot use BREAK to escape from a DO loop; either embed the loop in
    a macro and use RETURN to exit early, or rewrite the DO as a WHILE loop.



    Chdir

    Syntax: CHDIR WORD
    






    Set the current directory to be WORD, where WORD is any valid
    directory. It might be wise to enclose it in quotes,
    e.g. CHDIR "[-.more_data]", or use the cd macro.
    The new directory only affects SM,
    for example DATA or SAVE commands. When you exit
    SM, you will be back
    where you started. If the directory starts with a `~',
    the `~' will be replaced by the name of your home directory. This
    is the only
    place that `~' is significant; in particular it will not be recognised
    by the DATA command.(19)



    Your current directory is always available as the $cwd variable.


    Connect

    Syntax: CONNECT WORD1 WORD2 [ IF (expr) ]
    




    CONNECT draws line segments connecting the points in vectors WORD1 and
    WORD2. If the IF clause is present, only connect those points for which
    expr
    (see the section on vector arithmetic) is non-zero. Only contiguous
    points in the input vectors will be connected, resulting in a number of
    line-segments. If you don't want this behaviour, say something like

    set l = (z==1) ? 1 : 0  set x=xx if(l) set yy=y if(l) connect xx yy
    



    In fact, either or both of the WORDs may be replaced by
    `parenthesised expressions', i.e. expressions in parentheses. For example,

    CONNECT x (2*y)
    


    plots x against 2y.



    If WORD1 and WORD2 have different dimensions CONNECT will
    ignore the excess points in the longer vector. If you want to plot a
    constant value you'll have to explicitly promote it, for example

    CONNECT x (1+0*x)
    


    which makes a rather boring plot.



    To draw a line in a label you can either use CONNECT or DRAW, or use the
    TeX-macro \line to directly insert your line.



    Contour

    Syntax: CONTOUR 
    
    





    Makes a contour plot of an image read by the IMAGE command
    (see section Image).
    The contour levels are set using LEVELS;
    plot coordinates are taken to be those set by the
    LIMITS command, and contours are drawn in the current LTYPE. It is not
    possible to produce labeled contours.



    Any pixels whose value is NaN are ignored, as are any whose value
    equals the SM variable $missing_data; by default this is some
    very large number (usually 1e37). If a contour line runs into a missing
    data point it simply stops, rather than being made to join up with some
    other line that also runs into a missing point.



    See also DITHER for dithering images, IMAGE CURSOR for using cursors to
    get values from images, MINMAX for finding the minimum and maximum of
    images, and Arithmetic for extracting cross-sections of images.



    Ctype

    Syntax: CTYPE WORD
            CTYPE INTEGER
            CTYPE = expr
    









    With WORD, set the line colour to be WORD, if your
    display device supports
    coloured lines, where WORD must be one of default, white,
    black, red, green, blue, cyan, magenta,
    or yellow. The colours are those composed of three, zero, one, or two
    of the primary colours red, green, and blue. When a device is opened
    it sets default to some device specific value (e.g. white for
    xwindows, black for sunwindows).



    Initially, CTYPE INTEGER is another way of selecting the same colours
    as are available with CTYPE WORD, where CTYPE 1
    is the equivalent of the
    first colour listed above, or white (so default is 0).
    However, the CTYPE = expr
    command redefines the available colours to be the elements of the array
    given by expr. If it is arithmetic, each element of is interpreted as
    RED + 256*GREEN + 256^2*BLUE for the given colour, where 0 is off,
    and 255 corresponds to full intensity.
    If the expr is string-valued it specifies the names to be
    used for the colours that you have just defined. Any connection
    between the names and colours is, of course, up to you.


    You can get the current value of CTYPE with DEFINE ctype |,
    and vectors of the current ctypes and their names as CTYPE() and
    CTYPE(STRING).



    So another way to get
    white lines would be to say:

    CTYPE = { 0 255 0 } + 256*({ 0 255 255 } + 256*{0 255 0 })
    CTYPE 1
    


    while

    CTYPE 2
    


    would give green lines.

    CTYPE ={ black white green }
    


    would make your colour names correspond to reality again. You can use any
    names you like, you are certainly not restricted to the initial set.


    You can reset the colours to their default (i.e. correct) values using the macro
    reset_ctype.



    If you want to add a new colour you can say:

    CTYPE = CTYPE() concat 200 + 256*(100 + 256*100)
    CTYPE = CTYPE(STRING) concat 'pink'
    


    and delete one with

    foreach f {"" string} {
       set ct=ctype($f) if(ctype(string) != 'pink') ctype = ct
    }
    

    (see also macros add_ctype and del_ctype).



    Many devices (e.g. sunview) require you to specify
    a number of colours that is a power of 2, so asking for 70 colours
    will use up 128 slots. It is probably a good idea to
    use as few colours as possible, as they are scarce resources on most displays.
    You should also be aware that the display may use some of `your' slots
    for the background, so specifying 63 colours on (e.g.) a sun actually
    requires 64 (and asking for 64 will use up 128). If you specify more colours
    than are physically available, or more than the device driver thinks
    that you deserve, SM will interpolate your values of CTYPE for you.



    If you are using X11 (see section Device), you will probably need to use the
    -cmap flag when openinig your device if you want to allocate many
    private colours.



    The default colour is specified
    in the device drivers, or in the DC (Default Colour) graphcap
    capability, and is set whenever a device is opened, so don't try to
    modify it with a CTYPE = expr command. You can, however, override
    the default colour with a foreground entry in your `.sm' file;
    it should be the name of a colour (as listed above). You may also be able to
    specify a background colour (as background). This is either a colour
    name or a set of three integers in the range 0-255 specifying
    the red, green, and blue values. We allow you this chance to specify arbitrary
    colours because it's your only chance to affect the background, and you can't
    use a CTYPE = command to compose your own palette. On some devices
    the name of the background colour may be chosen from a wider selection;
    for example if you are using Xwindows you may use any name from the
    colour database.



    Cursor

    Syntax: CURSOR 
            CURSOR WORD1 WORD2
            CURSOR READ
    




    Display the cross-hair cursor to enable you to get positions (in user
    coordinates). The current cursor position is typed on the screen every time
    that you hit a key; some keys are special, specifically you can exit
    the cursor routine by hitting `e' or `q'. If you exit with `e', CURSOR issues a
    relocate command to set the current plot position to the cursor
    position, and puts the command in the history buffer. If you exit with `q',
    no entry is made in the buffer (but the current position is still updated).
    Usually successive positions overwrite
    each other, but if a digit is used to mark a point then the position is
    followed by a newline, so the next time you hit a key its position
    will appear on the next line. (You can remember that digits lead to
    numerous values appearing). If the verbosity (see section Verbose) is one or
    more, a message will be printed reminding you what keys to use.


    If you simply want to read the current position of the cursor, you can
    say CURSOR READ; this is mostly useful within macros (see, for
    example, animate in the macro file `3d').



    Many graphics devices have things called "GIN terminators".
    SM usually expects that this be set to `Carriage Return' with
    no extra characters, EOT is a popular (unacceptable) choice. If you
    have trouble check your graphics setup screen, then with your
    SM Guru who can look up in graphcap to see what is expected.
    If the local Guru were very friendly, he could change your GIN
    terminator to anything he wanted, even EOT, but he probably isn't.



    The second form enables you to define a pair of vectors WORD1

    and WORD2. SM provides you with a cursor, and every time that
    you hit a key it prints its position (just as above). If the letter is
    `e' it draws a point of the current type at the current position,
    prints the current position, and enters the (x,y) coordinates in the
    vectors; if you use `m' to mark a point the coordinates are not written
    to the screen, but the point is still added to the vectors. `p' defines
    the current point, and exits. Exit without defining another point with
    `q', so the sequence `e' `q' is equivalent to `p'. You can also
    abort with a control-C in which case WORD1 and
    WORD2 are unchanged.



    Note that if you want to use SPLINE on the vectors produced in this
    way, you should take care that at least one of the vectors is monotonic and
    increasing, or use the SORT command.


    See also IMAGE CURSOR which returns the value under the cursor as well
    as the position if an IMAGE (see section Image) has been defined.



    For devices with mice, if the buttons do anything, they should generate
    the characters `e', `p', and `q' (starting at the left).



    The SunWindows cursor is slightly different. The cursor position is given
    by a pointing finger (it's the best we could do), and
    SM won't see any characters typed at
    the keyboard until you hit a carriage return. Device sunwindows is
    obsolete anyway, you should simply switch to using the sunview driver.
    Its cursor has a bug, in that it only sees every other character
    typed at the keyboard. If I knew why I'd fix it.



    Data

    Syntax: DATA file
    





    Use file file as the source of data read with the READ command.
    The file is assumed to have numerical data in columns separated by spaces,
    or tabs. The range of lines specified by LINES is reset. If the file
    can't be opened for read, you will be warned. The variable $data_file

    is set to file.
    See the READ command to see how to read the data.
    You may need to quote the filename, e.g. DATA "/usr/file", which
    you can do by using the macro da: da /usr/file.



    Perverse people who wish to use filenames such as `12' or
    `3.14' will find that they get syntax errors. If they must
    persist DATA "3.14 " will work.



    Define

    Syntax: DEFINE name value
            LOCAL DEFINE name ...
            DEFINE name { value_list } [ \[ INTEGER, INTEGER \] ]
            DEFINE name < value_list > [ \[ INTEGER, INTEGER \] ]
            DEFINE name DELETE
            DEFINE name LOCAL
            DEFINE name ( expr )
            DEFINE name :
            DEFINE name |
            DEFINE name ? [ { prompt } ]
            DEFINE name ? [ < prompt > ]
            DEFINE name READ INTEGER
            DEFINE name READ INTEGER INTEGER2
            DEFINE name IMAGE
            IMAGE DEFINE name  value
            LIST DEFINE [ begin end ]
    





    All of these varieties of DEFINE define variable name to have some
    value, but
    as variables can be defined in all sorts of ways there are a good
    many possibilities. With the prefix LOCAL (which is allowed in front
    of any of the DEFINE commands), the variable will be local to the
    macro; (see section Local).



    Name is a single word starting with a letter, and
    containing only letters, digits, or `_', and may be a keyword.
    Whenever SM comes across

    $name, it is interpreted as a reference to variable name and
    $name is replaced by its value.
    (Note that some variables such as date are special as they always
    contain an up-to-date value, for an example try echo $date sometime.
    These variables are listed under DEFINE name |.)
    You can also evaluate expressions with $(expr), for example

    echo $(pi/2). The value can't be longer than about 80 characters,
    except for the value_list form in which case its length can
    be essentially infinite.



    If you just want to know if a variable is defined, then $?name
    is defined to have the value 1 if name is defined, and 0 otherwise.
    Variables are not usually expanded within double quotes or {}, but if you use
    the syntax $!name the variable will be expanded within double quotes;

    $!!name will be expanded anywhere.



    For the variants of DEFINE name value and DEFINE name value_list,
    value is either a word or number, or a list.
    The difference between using
    {} and <> to delimit a list is that keywords can appear within {},
    but variables are not usually expanded.


    With the optional [ INTEGER, INTEGER ] clause (I apologise for the
    notation in the manual; those [] are required) you can choose a
    subrange, just as SUBSTR (see section Strings) can choose a part of a vector
    element. For example,

      define s <"/abc/def">[1,-2]  echo $s
    


    prints

      abc/d
    


    Why is this useful? Because it provides a way of working around limits
    on lengths of vector elements; otherwise this example is equivalent to

      define s (substr('/abc/def', 1,-2))  echo $s
    


    DEFINE name DELETE, deletes a variable (see
    also the macro undef to undefine variables).


    DEFINE name LOCAL, which is only allowed within macros,
    creates a variable which will only be visible from the current macro, and from
    macros called by it (see section Local).
    Such local variables are automatically destroyed when
    leaving the macro within which they were created, and may not be explicitly
    deleted. This is similar to the behaviour of numbered variables, except that
    they really are local (i.e. they are only visible in the macro, and
    not in its descendents; SM's LOCAL variables have nested scope rather than
    being truly local).



    An alternative is to prefix the DEFINE command itself with LOCAL;
    DEFINE me LOCAL DEFINE me RHL is exactly equivalent to
    LOCAL DEFINE me RHL.



    A common use for DEFINE LOCAL is:

       define i local
       foreach i { sorbus aucuparia } { set $i local }
    


    to protect a FOREACH (or DO) variable, and all local vectors, in one simple
    line. It is because such loop variables are automatically destroyed that
    attempts to delete local variables are not reported at VERBOSE levels of
    1 or less.



    DEFINE name ( expr ) defines a variable to have the value of
    a (scalar) expression. When possible, it is more efficient to use
    vectors to perform calculations on scalars, rather than putting them
    into variables. It is also more efficient (and more obscure!) to use
    numbered variables (macro arguments) than real named ones.
    As a special dispensation, the expression can be an element of a
    string-valued vector (elements of arithmetic vectors are allowed too
    of course).


    DEFINE name : defines the variable name from
    the environment file. If name can't be found, and is capitalised,
    SM will look for it in the environment (as a logical variable for VMS
    users).



    DEFINE name | is used to define a variable
    from an internal SM variable such as expand or angle.
    These variables can be listed with LIST DEFINE | (or by

    LIST DEFINE if VERBOSE is two or more); a possibly incomplete
    list is: angle, aspect, ctype, cwd,
    date, exit_status, expand,

    fx1, fx2, fy1, fy2,
    gx1, gx2, gy1, gy2,
    ltype, ltype_expand, lweight,

    nx, ny, ptype,
    sdepth, sheight, slength,
    distance, theta, phi,

    uxp, uyp, verbose,
    xp, and yp. The
    current plot limits are fx1 etc., (or gx1 etc. in device
    coordinates), the size of the screen (in pixels, or dots, or whatever the
    hardware uses) is nx * ny, the current position (in user
    coordinates) is (uxp,uyp) ,
    the current position (in plot
    coordinates) is (xp,yp), exit_status is the return code from the
    last ! command,

    sdepth, sheight, and slength are the depth, height, and
    length of the last string drawn to the screen,
    distance, theta, and phi are the viewpoint for surface
    plots (see section Viewpoint),
    and the rest should be obvious. In the case of angle, expand,
    and ptype, if you used a vector to set (e.g.) the expansion, the
    value given will be that of its first element, and there's also
    an extra value giving its dimension. This allows you to say things like

    if(dimen(<$angle>) == 2) { echo You used a vector angle command }
    






    This sort of variable changed a little with version 2.1.1. The variables
    that you can use have not changed, but their usage has
    slightly. They are all defined for you when SM starts and each is always
    correct, tracking the current value of the corresponding internal variable.
    For example, try echo $angle\n angle 45 echo $angle. If you now
    say define angle |, $angle will cease to track the internal
    value and will remain fixed (the same effect can be achieved with

    define angle 45). When you say define angle delete it will
    once more track the internal value. Your old code will continue to work,
    but in many cases it is possible to remove the explicit definition
    with |. This special sort of variable will not be SAVEd,
    and will not show up if you list the currently defined variables (unless
    VERBOSE is two or more).



    DEFINE name ? will prompt you for the value
    of name at the keyboard, using the prompt string if given,
    otherwise the name of the variable. The old value of the variable (if
    defined) is printed within [], and is taken to be the default if you
    simply hit carriage return. As previously discussed, the difference between
    {} and <> is in the treatment of keywords and variables. If you
    don't want to use {} (probably because of something weird to do with when
    variables are expanded), you can always use quotes within <>.



    The versions of the DEFINE command including READ define variables from
    the current data file. DEFINE name READ INTEGER
    sets name to be line INTEGER of the current data file, while
    DEFINE name READ INTEGER INTEGER2

    defines name to be word INTEGER2 of line INTEGER.
    name is subject to the usual restrictions. If the line begins with
    a # the first character is simply ignored when defining variables.


    DEFINE name IMAGE defines a variable from a file read with the
    IMAGE or TABLE command. Currently this only works for NX, NY,
    X0, X1,
    Y0, Y1, or any keyword from a FITS header. Any minus signs
    (-) appearing in name are converted to underscores (_),
    as SM doesn't allow - in a variable name.



    You can define further such variables using IMAGE DEFINE name value,
    a facility that is chiefly useful in connection with the WRITE IMAGE command
    (see section Image).



    LIST DEFINE lists all currently defined variables, or all those which are
    between begin and end alphabetically (asciily). You can
    use LIST DEFINE | to list internal variables, or LIST DEFINE IMAGE
    to list image variable (see section List).


    Examples

    DEFINE v1 5.993
    DEFINE label1 KPNO
    DEFINE label1 < National Optical Astronomical Observatory > 
    DEFINE v2 ($v1 + 3.4)
    DEFINE v1 DELETE
    DEFINE age ? { How old are you? }
    DEFINE macros : WRITE STANDARD "$!macros"
    


    (Note that we couldn't have used <> to prompt for your age, because then
    the ? after you would be treated as a keyword).



    To illustrate the DEFINE name READ commands, consider a file with
    the following lines:

    This is a file containing astronomical data
    Magnitude  Intensity  Wavelength  Error
    


    Then using the DEFINE commands as follows:

    DEFINE title READ 1
    DEFINE labelx READ 2 3
    


    will assign the string This is a file containing astronomical data
    to the variable title, and the word Wavelength to the variable
    labelx, so you can say XLABEL $labelx.



    Delete

    Syntax: DELETE [ INTEGER1 [ INTEGER2 ] ]
            DELETE HISTORY [ ! ]
            DELETE HISTORY [ INTEGER1 [ INTEGER2 ] ]
            DELETE WORD
    




    Delete commands INTEGER1 to INTEGER2 (inclusive) from the
    history buffer. If the INTEGERs are not present, delete the last
    command. DELETE 0 will delete all history commands. If the INTEGERs
    are negative they are interpreted relative to the current command, so

    -1 is the last command.



    The DELETE HISTORY commands are identical to the DELETE commands, except
    they themselves do appear on the history list; they are preserved for
    backwards compatibility and because DELETE HISTORY \n can be used to prevent
    a command from appearing on the history list (the macro del1).
    If a macro contains a DELETE HISTORY, or
    calls a macro that contains one, or ... the macro will not appear on the
    history list.
    Traditionally, this meant that if there were two (or more) occurrences
    of DELETE HISTORY the
    previous command(s) were also be deleted, but in SM version 2.2.1 this
    has been changed, and DELETE HISTORY will only delete the last command
    typed at the keyboard. If for some nefarious purpose you really do want
    to delete older commands too, you can say DELETE HISTORY ! and the command
    will work the old way.



    DELETE WORD deletes the vector WORD (see SET WORD

    or READ WORD for how to define vectors), MACRO name DELETE
    is used to delete a macro, DEFINE name DELETE deletes a variable.



    Device

    Syntax: DEVICE WORD [ rest_of_line ]
            DEVICE INTEGER [ WORD ] [ rest_of_line ]
            DEVICE META WORD
            DEVICE META CLOSE
    





    (The DEVICE INTEGER form is retained for historical interest and
    backwards compatibility only.)



    Choose a device to plot to. Exactly which devices are available depends
    on your hardware configuration and how SM was compiled. You can list
    available devices with the LIST DEVICE command (see section List).
    When you specify a device the previous device is closed, which
    may lead to some action being taken (for example, sending a plot
    to a printer).



    When a device is opened it is looked up by name in the `graphcap' file
    (see section The Stdgraph Graphics Kernel).
    In some cases all the information that SM needs to plot to the device is
    available there (for example xterm or postscript); such devices
    are referred to as stdgraph devices. Otherwise the graphcap entry
    will contain the name of the real device driver, for example x11.
    Anything else on the line is passed to the device driver.



    In particular, for the stdgraph devices an argument that is not
    specifically processed by the device is taken to be the name of a file to save
    the plot in. Thus device postscript foo.ps creates a plot in a file
    called `foo.ps'(20)



    The pseudo-device META is special (see section Meta). It is used to support
    metafiles, which allow you to save a plot as you display it, and
    finally send it to a different device.



    Especially for hardcopy devices, you may have to specify which one you want,
    e.g. DEVICE postscript latypus. Because this depends on how your
    local graphcap was configured, you'll have to see your Guru for guidance;
    see section The Stdgraph Graphics Kernel.



    When a device is opened, it is set to the current CTYPE, LWEIGHT, and
    LTYPE, and the proper aspect ratio is chosen to make text and plotted
    points look nice. It also looks for an entry foreground in your `.sm' file, and uses it as the default colour for the device (this
    overrides any default that the device driver may have specified). The
    device driver may (or may not) choose to honour a background

    entry as well. These colours may be specified either as names (see
    CTYPE), or the background colour may be given as a set of three numbers,
    which are interpreted as the
    red, green, and blue intensities in the range 0 - 255. Some devices may allow
    you a wider selection of background names; for example the Xwindows driver
    allows any name from the colour database.




    If you want to use some foreground colour that CTYPE doesn't usually
    understand you must define it before opening the device. For example, after
    defining the macro

    add_colour 4 ## add a colour to the standard set. Usage: name r g b
                 CTYPE=<0 255 0 255 0 0 0 255 255 $2> + \
                     256*(<0 255 0 0 255 0 255 0 255 $3> + \
                           256*<0 255 0 0 0 255 255 255 0 $4>)
                 ctype=<default white black red green blue cyan magenta yellow $1>
    
    


    you could say add_colour gray 200 200 200, after which `gray' would
    be a perfectly good `foreground' colour.



    Different ways of plotting to
    the same device (e.g. portrait or landscape) are accommodated by using
    different drivers (e.g. postport and postland for postscript
    devices) rather than some magic command to SM.


    • Nodevice: The NULL device
    • Borland: Borland Graphics on a PC
    • Metafile: Graphics Metafiles
    • OS/2: OS/2 Presentation Manager
    • Postscript: Postscript Devices
    • SGI: The Silicon Graphics (and RS-6000) Device
    • Stdgraph: The General Device Driver, using Graphcap

  • SunView: The SunView (and Sunwindows) Devices
  • Tk: A Tk Widget
  • UnixPC: The Unix-PC Device
  • MS-Windows: PC Graphics under MS-Windows
  • VAX-UIS: VAX/VMS UIS$ device
  • XWindows: The X-Windows Devices (X10 and X11)

  • The NULL device



    DEVICE nodevice is always available; it is a bit bucket where
    plot commands may be sent never to be seen again, the equivalent of
    /dev/null (under unix) or nl: under VMS.



    It is useful because it is always available; it's the current device when
    SM is started.
    Because SM submits plots only when the current
    device is closed, and because opening nodevice closes the current
    device, it is also used by the hardcopy command (in fact

    hardcopy is a macro that expands to DEVICE nodevice).



    Borland Graphics on a PC



    SM works on a PC running DOS either by using Borland's graphics or windows
    (see the section on MS-Windows); this section describes the former.
    SM was ported
    to run under DOS by Laurent Bartholdi, who also wrote the BGI and MS-Windows
    device drivers. He gets all the credit for the PC version of SM, but of
    course he is not responsible for any remaining bugs (some of which we
    almost certainly created while merging the PC and regular versions).



    The graphics drivers, the `.bgi' files, are assumed to be in a directory
    given by the DOS BGIPATH environment variable; alternatively you
    can specify a bgipath variable in your `.sm' file.



    The DEVICE command takes two optional arguments:
    DEVICE bgi devtype mode. The first, devtype, is the type of
    hardware that you are running. If you want the driver to try to figure
    this out for itself, use DEVICE bgi detect (this is the default
    if you omit devtype entirely); for a listing of
    possibilities say DEVICE bgi ?. The second argument, mode,
    determines how SM switches between screen and graphics modes. Your options are
    none, swap (the default), or switch; experiment to
    see which works better for you. At present, a certain amount
    of `snow' is left at the top of the graphics screen. This is very dependent
    on the details of your graphics card, and we see no general way to prevent
    its appearance.



    Once you have decided what options you like best, you can set a variable
    stdmode in your `.sm' file (e.g. to detect swap) to save
    yourself some typing.



    There is a `hot key', ALT-F1, that can be used to toggle between text
    and graphics mode.


    The current return value of the function coreleft is available as
    $coreleft (which is like any other DEFINE var | variable).



    OS/2 Presentation Manager



    The OS2PM driver is used to display graphics in a Presentation Manger
    graphics window under OS/2 v2.x (you should specify your terminal as

    os2pc). Two optional arguments are currently supported:

    -n

    Disable all backing for the graphics window. This will
    significantly increase the drawing speed, but the contents
    of the graphics window will not be redrawn when portions of
    the window are uncovered or when the window is resized.
    -gWxH

    Specify the window geometry. The W and H parameters should
    contains the WIDTH and HEIGHT of the graphics window in pixels.


    If DEVICE os2pm is specified without the -gWxH argument the graphics window
    will be created the same size as the last previously displayed window. If
    this is the first time the graphics window is created it will default to
    600 x 400 pixels.


    For example,

         DEVICE os2pm -g800x500
              .
              .
              .
         DEVICE os2pm -n
    


    The first DEVICE statement will produce an 800 x 500 pixel graphics
    window with backing enabled. The second will again produce an 800 x 500
    pixel window but with no backing.



    Graphics Metafiles



    As described elsewhere (see section Meta) SM can save graphics commands
    to a metafile while producing a plot on your screen.



    Postscript Devices



    Strictly speaking, there are no postscript devices, merely postscript
    drivers in stdgraph (see section The Stdgraph Graphics Kernel). On the other hand, SM is able
    to drive postscript printers in a totally transparent way, so a user
    can think of SM's postscript capability as discrete drivers. In the
    following descriptions the arguments to the device command are referred to
    as $1, $2, and so on. Aliases are listed in parentheses
    after the device name, so post_colour can also be called

    post_color.
    Those
    currently supported are:

    postscript (POSTSCRIPT)

    The basic driver; produces 8x8inch output on the default printer.
    postport (POSTPORT)

    A full-page portrait-mode plot.
    postland (POSTLAND)

    A full-page landscape-mode plot.
    post_colour (post_color)


    Like postscript, but generates a colour postscript plot, and sends
    it to a printer called ps_colour0.
    blackpostscript

    Like post_colour, but uses a black background.
    postfile (postencap)

    Like postscript, but generate an encapsulated postscript file in $1.
    postlandfile


    Like postland, but generate an encapsulated postscript file in $1.
    post_remote (postscript_remote)

    Like postscript, but prints to a printer $2 on host $1.
    postland_remote


    Like postscript, but prints to a printer $2 on host $1.
    postport_remote

    Like postport, but prints to a printer $2 on host $1.


    For an example of defining your own postscript device that takes a printer
    name as an argument, see section The Stdgraph Graphics Kernel.



    The Silicon Graphics (and RS-6000) Device



    The Silicon Graphics device driver works. If you read this and want
    more documentation, send mail to us and we'll get to it.


    The General Device Driver, using Graphcap



    By far the majority of devices that SM supports are driven through the
    stdgraph device; a partial list includes tek4010, tek4012,
    pericom,
    selanar, (or hirez ),

    versaterm (or macvt ),
    vt640 (a vt100 with retrographics ), vt240 in REGIS mode,
    hard4012 or hard4010 for a tek4010 that really has no decent
    ascii mode, tek4025, wyse1575, cit414a or 414a.
    We also support graphcap drivers for Postscript, QMS, and LN03 laser printers,
    (device names postscript, qms and ln03). Stdgraph can also
    cooperate with raster devices, for instance to plot on a lineprinter.



    For the stdgraph (i.e. default) device driver the final word on
    the command line (if present) is taken to be the name of a file to receive
    the output that would ordinarily go to the screen, so if you say

    device graphon outfile
    


    and then create a plot nothing will seem to happen. However, if you close the
    device and write `outfile' to the terminal (maybe using /passall
    if you are running VMS) your plot will appear.
    In addition, any word
    beginning with a colon will be taken to be part of a graphcap entry
    (see section The Stdgraph Graphics Kernel), and prepended to the entry in the graphcap file
    for your chosen device.
    For example, if you wanted to save your postscript output in a file
    you could say

    dev postscript ":SY=echo File is $F:"
    


    which would replace the SY entry that sent the output
    to the printer by a new one that merely tells you what the file is called.
    If you'd prefer to give it a memorable name, you could say

    dev postscript ":SY=echo File is \$F:OF=name:"
    


    or

    dev postscript :SY@: :OF@: name
    
    


    (it doesn't matter if the entries are all in the same word). The former
    redefines the output file OF to be "name", and makes SY
    tell you so. The latter disables both OF and SY, so the generated
    postscript would ordinarily go to the terminal (just like any other
    graphics terminal), but a file `name' is specified, so the output is sent
    there instead.



    If you find yourself frequently wanting to use a customised stdgraph device,
    this mechanism can become rather tedious; you'd rather simply invent the
    device and be done with it. The proper way to do this is to create a local
    graphcap file (see section The Graphcap File), and add your new device to it.
    For example, if you wanted to define a postscript device that took the name of
    the printer as its argument, you'd put an entry

    mypostscript|like postscript, but specify the printer as its argument:\
            :SY=lpr -r -P$1 $F:TC=postscript:
    


    in your file, and merrily proceed with making beautiful plots
    using DEVICE mypostscript fred. If you always want to use your new
    device you could call it postscript and in effect redefine the
    old postscript device (note carefully that I said :TC=postscript:

    not :tc=postscript:; if I hadn't, an infinite loop would have resulted).



    The SunView (and Sunwindows) Devices





    As the sunwindows driver is now obsolete, and may well disappear in
    some future release, you should use the sunview driver instead.


    If you insist on using the old driver, it
    must be run from within a gfxtool.



    The SunView window driver supports a subset of the usual SunView
    command line arguments, specifically:

    -WH

    Summarise options
    -Wi

    Open window as an icon
    -Wl label


    Specify label for the window (default: SM)
    -Wn

    Don't label window
    -WP x y

    Position of icon
    -Wp x y

    Position of window
    -Ws w h
    Size of window

    The standard SunView popup `frame' menu has been modified to
    allow you to erase the graphics screen. It is perfectly safe to use
    the menu to quit the graphics window, in this case the next
    device sunview command will create a new one. If SM
    thinks that the window is active when you try to kill it, it will warn
    you; failing to believe it may result in a cascade of complaints to
    the console window. There is a bug in the cursor routine (I claim that
    it is a SunView bug) that means that SM sees only every other key-stroke.



    A Tcl/Tk Widget


    It's possible to build SM to support a Tk widget (on unix boxes only; the
    SM Tk graphics are based on X11). If this interests you, specify the TK
    device when building SM, then build tkSM in the callable directory and say

       tkSM smtk.tcl
    


    to run an example that we wrote.
    The source code should be easily modifiable to add features that your
    application needs.



    The Unix-PC Device




    On a Unix-PC DEVICE upc opens a window of 304 by 192 pixels,
    which is about 4 by 4 inches. To quote the author
    (Peter Teuben, teuben@astro.umd.edu),


    This whole Unixpc version is an experimental version, take
    it as is, it works on my configuration, but may not work on yours.

  • I'm playing with allowing a second and third parameter to
    the upc device name, which would allow you to change the default size of 304
    by 192 pixels (The size in X must be a multiple of 16 though).
    Right now I have it check environment variables YAPP_X and
    YAPP_Y, but this may not work satisfactorily.

  • I spawn windows using the public domain program `wlogin',
    this may be of some importance if your `upc' device in SM fails.


    I don't have a Unix PC, so I can't work on this driver.



    PC Graphics under MS-Windows



    This section needs more work; send mail to rhl@astro.princeton.edu.



    VAX/VMS UIS$ device



    the VAXUIS driver is used to display graphics on a VAX Workstation
    using the VAX UIS$ library routines. The optional X and Y parameters
    specify the size of the graphics window ( in centimeters ) created on
    the workstation screen.



    If called without the optional X and Y parameters the graphics
    display window will be the same size as that previously displayed.



    If the X and Y parameters are not specified the first time the
    DEVICE vaxuis command is issued, the graphics display window will
    occupy 1/2 the height and 1/2 the width of the workstation screen.



    For example, to create a 15 cm wide x 10 cm tall display window say:

    		DEVICE vaxuis 15 10
    
    


    The X-Windows Devices (X10 and X11)





    There are two X-Windows drivers, one for X10 and one for X11 and they
    differ in their treatment of command line arguments. The X11 driver
    is considerably more sophisticated and will be treated first.




    The X11 window driver (device x11) supports a subset of the standard
    command line arguments, specifically (the X-resources names appear in
    parentheses at the ends of the descriptions):

    #geom

    Specify icon geometry (.icongeometry)
    -bd n

    Border width (.borderwidth)
    -bg colour

    Background colour (.background)

    -device n (.device)

    Use X11-device n
    -cmap

    Use a private colour map for this device (.colormap)
    -colormap


    Use a private colour map for this device (same as -cmap). (.colormap)
    -colourmap

    Use a private colour map for this device (same as -cmap). (.colormap)
    -cmap

    Use a private colour map for this device (.colormap)
    -display name


    Name of display to open (.display)
    -fg colour

    Foreground colour (.foreground)
    -fn fontname

    Name of hardware font to use (.font)
    -geometry geom


    Specify window geometry (.geometry)
    -help

    Summarise options
    -kbdfocus

    Preserve keyboard focus (the same as -focus). Without this, some window
    managers transfer focus to the graphics window when it is created; probably
    not what you want (.kbdfocus)
    -iconic

    Open window as an icon (.iconic)

    -name name

    -ndevice n (.ndevice)

    Allow up to n X11 devices
    -nocurswind

    Do not show the cursor position while in cursor mode (same as -nocw)
    Specify name of window (.name)

    -preopened display_id:window_id

    Specify device and window id's
    -synchronise

    Synchronise with server (debugging only) (.synchronise)
    -title title

    Specify title of window (.title)


    Where geom is a standard geometry string of the form WxH+-X+-Y,
    and the preopened option is for a programme calling SM
    non-interactively.
    All options may be abbreviated, so

    device x11 -i #-1+1 -g 512x512+100+100
    


    specifies that the graphics window be created as an icon in the top
    right hand corner of the screen, and that the real window should be
    512*512 and positioned near the top left corner.



    SM is able to open more than one x11 device (by default it can handle 5);
    see the -device and -ndevice options.
    You can say device x11 -dev + to switch to the next open X11
    device; device x11 -dev - switches to the previous one.


    If you want to raise your graphics window so that you can see it, you
    can either use the window manager, reopen the device (dev x11),
    erase the screen, or use the PAGE command.



    On hardware that doesn't support a backing store (or if you have chosen
    to disable a backing store when compiling the X11 driver) the screen will
    only be refreshed when it is active or when SM is waiting for input. If
    your operating system doesn't support the select() system call you
    may be even worse off, but reopening the device (device x11) should
    still result in the screen being redrawn.



    If you use CTYPE = expr to ask for more than a small number of
    special colours (see section Ctype), you will probably need to specify

    -cmap to get your own colour map; if you don't SM may well
    complain about being unable to allocate colours.




    The X10 driver is known as xwindow, and you can optionally
    specify a device to open, and a window ID, on the command line. For
    example

    device xwindows DEVICE unix:0
    


    will open a graphics window on device unix:0. (You can
    optionally include a ID number after the DEVICE if you are calling
    SM from a programme, and have already opened the window).
    The X10 driver doesn't bother to remember any hardware characters that
    you may have
    written on a graph, so that if you refresh the window they won't appear.
    If this worries you can, as always, force the software character set
    with an expand 1.001.



    Dither

    Syntax: DITHER x y min max fac
    





    Generates a dithered represention of an image read by the IMAGE command
    (see section Image). The vectors x and y are set to points whose density
    is proportional to the image's intensity (only values between min and
    max are considered).


    Any pixels whose value is NaN are ignored, as are any whose value
    equals the SM variable $missing_data; by default this is some
    very large number.



    The dithering algorithm used is Floyd-Steinberg, and each pixel of
    the image is represented by (up to) fac*fac points, where (of course)
    all fac*fac points are only used for intensities greater than equal to
    max. Even the case fac == 1 can produce nice output for suitably sampled
    images.



    The resulting vectors are usually plotted as ptype 1 1.


    An example of dithering an image would be:

    IMAGE image_file
    DITHER x y 0 3000 4
    PTYPE 1 1
    POINTS x y
    


    Of course, you can be more sophisticated; for example:

    define min 3000  define max 60000  define gamma 2
    set ii = image[*,*]
    set ii=(ii < $min ? 0 : ii > $max ? 1 : (ii-$min)/($max - $min)
    set image[*,*] = (1 + $gamma)*ii/(1 + $gamma*ii)
    dither x y 0 1 4
    define v local foreach v (x y) {
       set $v=$v + 0.5*random(dimen($v))
    }
    POINTS x y
    


    or

    DITHER x y 0 3000 1
    expand 0.3 + IMAGE(x,y)/3000
    PTYPE 4 3
    POINTS x y
    


    See also IMAGE for reading images, CONTOUR for contouring them, IMAGE CURSOR
    for using cursors to get values from images, MINMAX for finding the minimum
    and maximum of images, and Arithmetic for extracting cross-sections of images.



    Do

    Syntax: DO variable = start, end [ , incr ] { commands }
    



    While the value of $variable runs from start to end, the commands
    are executed. The optional increment defaults to 1. It is not possible
    to change the value of the loop variable inside a loop (or at least it
    has no effect on the next iteration). To break out of a loop you have
    to break out of the current macro as well with RETURN (see section DO and FOREACH loops, WHILE loops, and IF statements).



    For example,

    
    DO i=1,10,0.5 { WRITE STANDARD $i } 
    


    will write 1 1.5 2 2.5 ... 10 to the terminal. The commands may be
    spread over several lines.



    Dot

    Syntax: DOT 
    




    Draw a point at the current location (set by RELOCATE, DRAW, etc.) in the
    style determined by PTYPE. The point's size and rotation are governed by
    EXPAND and ANGLE.



    To insert dots into labels, it may be easier to use the `TeX'
    definition \point or \apoint which inserts a dot of a
    specified PTYPE into a string (see section SM's Fonts).


    Draw

    Syntax: DRAW #1 #2
            DRAW ( #1 #2 )
    




    Draw a line from the current position (set with, for example RELOCATE) to
    (#1, #2) in user coordinates. If the parentheses are present, use
    screen coordinates.



    Edit

    
    Syntax: EDIT function key_strokes 
    




    Bind a function to a set of key_strokes for the editor.
    For example, EDIT refresh control-R makes the control-R key
    refresh the screen. A complete list of functions is given in the
    `Changing Key-Bindings' section in the main part of this manual (see
    under `bindings' in the index). Each character in the key sequence can
    be specified as a character, e.g. `a' or the single character
    `control-A',
    as `control-c' representing the single character control-c as the two
    character sequence `^' followed by `c', or by `\nnn'
    where nnn is an octal number (e.g. EDIT refresh \022).



    In order to use multiple key sequences
    (e.g. control-Acontrol-Bcontrol-C) you must first undefine
    any sub-sequences, in this case control-A and control-Acontrol-B,
    by making them illegal -- EDIT illegal control-A.


    See READ for how to define a set of keys from a file, and
    KEY for how to define keys to execute commands.



    Environment Variables

    Environment (`sm') Variables
    




    SM environment variables are defined in `.sm' files, which are searched
    for along a path which typically consists of
    the current directory, your home directory, and then some system place. You
    can specify your own search path by setting the environment (VMS: logical)
    variable SMPATH.
    If ~ appears in a path it is interpreted as your home directory unless you
    specified -u NAME when starting SM, in which case it will be interpreted
    as NAME's home directory instead.
    Alternatively, you can specify the name of the environment file using the
    `-f' flag on the command line; if it starts with a `/' it will be taken
    to be an absolute path name, otherwise it will be taken relative to the
    current path.


    If you invoke SM with the -f or -u
    flags, the are not passed on to raster devices, so if you plot
    to a device that invokes rasterise it will use the .sm files
    specified by $SMPATH.



    Each line of the files is taken to consist of a variable name, and the
    rest of the line which is taken to be its value. Any variable may be
    accessed using the DEFINE name : command, which defines name
    from the environment file.



    Comments run from `#' to the end of the line.
    If the first character of a line is a `@' or `+' the name is taken to start
    with the second character. A `@' means that the entry isn't present, and
    that SM should stop searching the path for it. A `+' means that SM should
    keep on searching the current `.sm' file, and then the rest of the
    search path, looking for more entries with the same name. If it finds one,
    the second value is added to the end of the first (and if the second
    occurrence also had a `+' specified the search continues).



    Some entries in the environment file are special to SM, although
    you are free to use them to your own ends as well. For most of those for
    which SM is only interested in whether the variable is defined, a value
    of 0 means that it shouldn't be defined. The variables are:

    background

    The background colour for plots
    case_fold_search

    If non-zero, make searches case insensitive
    default_font


    The default font for labels; you can also set this interactively, e.g.
    expand 1.001 define default_font "\oe\3".

    device

    Your initial graphics device
    edit

    A file of keybindings to read (see section Changing Key-Bindings).
    fan_compress

    Apply fan compression when connecting lines. This was donated by a user, and
    is intended to reduce the number of lines actually plotted to the device;
    whether it is useful is not clear. The reference is
    IEEE Computer Graphics and Applications, March 1989,
    `Faster Plots by Fan Data-Compression', by R.A. Fowell and D.D. McNeil
    .

    file_type

    The type of 2-D image for the IMAGE command
    filecap

    The filecap file to use (default: same as graphcap)
    line_up_exponents

    Force an extra space before single-digit exponents in axis labels
    fonts


    The name of the binary fonts file
    foreground

    The foreground colour for plots
    graphcap

    The graphcap file to use
    help

    The help directory
    history

    The length of the history list (default: 80)

    history_char

    The character used to recall commands (default: ^)
    history_file

    File to save history in
    macro

    The default macro directory

    macro2

    Your private macro directory

    missing_macro_continue

    If defined, a reference to a missing macro isn't a syntax error
    name

    The name SM calls you by
    noclobber

    Refuse to overwrite existing files with MACRO WRITE or PRINT.
    overload

    If non-zero, overload some commands
    printer


    The default printer (see hcopy and hmacro)
    prompt

    The initial value of SM's prompt
    prompt2

    The initial value of SM's secondary prompt
    remember_history_line

    Remember which line you last reused
    save_file

    Default file to save a SM session in

    save_read_ptr

    Save the position of the read pointer between READ commands
    temp_dir

    The directory for temporary files
    term

    Default terminal, over-ruling TERM
    termcap


    The file describing terminals to SM
    TeX_strings

    Use TeX-style strings for labels
    traceback

    Print the macro stack following an error
    uppercase

    Define uppercase versions of some macros
    x_gutter

    y_gutter

    Modify the spacing between windows when using the WINDOW command.
    (These are not actually read from the `.sm' by the default
    startup macro, you have to set them yourself).


    Under Unix, you should omit the termcap entry, or point it at
    `/etc/termcap'. Also under Unix, SM knows how to look up your
    name, so you can omit the name entry. If you try to use a name
    with more than one word, SM will use the first so you'll have
    to call yourself `my_lord' rather than `my lord' (the `_' will be
    replaced by a space).


    Some of these are used directly by SM (e.g. help, fonts,
    but some are merely used by the startup macro to set the initial
    value of SM variables (e.g. TeX_strings, file_type).
    Other names may be used by the default startup macro, e.g.
    macro2 to specify a private macro directory or

    term to specify the terminal that you are using. See the
    discussion of startup under `useful macros'.



    Erase

    Syntax: ERASE 
    



    ERASE erases the graphics screen. The macro era erases the
    screen without appearing on the history buffer. If you want to start a
    new output page on a hardcopy device use the PAGE command.



    You may be able to erase individual lines with LTYPE ERASE, if you can
    you should look at the macro undo.



    Errorbar

    Syntax: ERRORBAR WORD1 WORD2 expr INTEGER
    



    ERRORBAR is analogous to POINTS; it draws one-sided error bars on
    all points defined by vectors WORD1 and WORD2, where the
    length of each errorbar is set by the corresponding value in expr. INTEGER is 1 to put the bar along the +x direction, 2 for
    +y, 3 for -x, and 4 for -y. Use EXPAND to govern the size of the caps.
    In fact, instead of either or both of WORD1 and WORD2 you
    can use an expression in parentheses,
    for example ERRORBAR (lg(x)) (lg(y)) 120 1.



    See also the macros ec and err for backwards compatibility with
    Mongo, and error_x and error_y to produce (symmetrical)
    two-sided errorbars.
    There is also a macro logerr to draw errorbars on logarithmic plots.



    Expand

    Syntax: EXPAND expr
    





    EXPAND expands all characters and points, its default is 1.0. Note that the
    EXPAND factor is used in determining the plot window size in the WINDOW
    command. This means you should declare your EXPAND size to SM (if other
    than the default) before you use WINDOW. The current value of EXPAND
    is available as a DEFINE expand |.



    If EXPAND is set to exactly 1, and ANGLE is exactly 0, then SM
    will use hardware fonts, when available, in writing labels. This is faster,
    but if you don't like it say "EXPAND 1.00001", or "ANGLE 0.00001",
    or use a \r explicitly to select the roman font.



    EXPAND can in fact be given a vector of values, which are used for
    each point in a POINTS command. This supersedes the use of a fractional
    PTYPE (although we still support it as a quaint anachronism). Using
    vectors for both ANGLE and EXPAND makes it easy to draw a vector
    field, see (for example) the vfield macro.

    If more points are specified than
    the dimension of expr, the first element will be used for the excess.



    Fft

    Syntax: FFT n pexpr1 pexpr2 WORD1 WORD
    




    Fourier transform 2 vectors (treated as the real and imaginary parts
    of a complex vector), returning the answer in the two vectors WORD1 and
    WORD2. The input vectors may be the names of vectors or expressions in
    parentheses. The direction is specified by n, either +1 for a forward
    transform, or -1 for an inverse.


    The dimension of the vectors need not be a power of 2, but the transform
    is more efficient if it is. The worst case is when n is prime, in
    which case this command performs a slow Fourier transform in O(n^2) time.



    Foreach

    Syntax: FOREACH variable ( list ) { commands }
            FOREACH variable { list } { commands }
            FOREACH variable WORD { commands }
    




    In the first two forms, the value of variable is set to each
    element of list in turn,
    and then the commands are executed. An example would be

    var ( alpha 2 gamma ) { WRITE STANDARD $var }
    


    which would write alpha, 2, and then gamma to the
    terminal (see section DO and FOREACH loops, WHILE loops, and IF statements).



    The form with {} can be useful if you want the list exactly as you type it,
    for example

    	FOREACH f { 0.1 $date } { echo $f }
    



    The form FOREACH variable WORD ... is used to iterate over a vector,
    either arithmetic or string. For example,

            SET str={Sorbus Aucuparia David Monger}
    	FOREACH f str { echo $f }
    
    


    It is often useful to define the FOREACH variable to be LOCAL (see section Define),
    e.g. DEFINE f LOCAL in the last example.


    Format

    Syntax: FORMAT [ x-format-string y-format-string ]
    




    Allow the user to specify the axis tick label formats. The format should be
    given as a standard C (e.g. %4.1g) or Fortran (e.g. F10.4).
    This format
    will be in effect until unset by issuing the FORMAT command with no argument,
    in which case SM will figure out the best format for you, or until you
    issue a new FORMAT command with new format strings.



    If a format is specified as "0", the format string is left unchanged;
    if it is given as "1", the default value is reinstated. The command
    FORMAT 1 1 is thus equivalent to FORMAT.



    Grid

    Syntax: GRID [ INTEGER1 [ INTEGER2 ] ]
    




    Grid draws a grid at either major ( INTEGER1 = 0 ) or
    minor ( INTEGER1 = 1 ) tickmarks within a box.
    The default is INTEGER1 = 0. You can use INTEGER2 to specify
    only drawing an x- or y-axis grid: if INTEGER2 is omitted or 0,
    draw both x and y; if it's 1 only draw x; if it's 2 only draw y (3 is
    equivalent to 0).



    Help

    Syntax: HELP [ word ]
    




    The HELP command tries to help you with word. If possible, it
    prints the entry from the help directory specified in your `.sm' file, the definition of word if it's a macro,
    the value of word if it's a variable, and the HELP string if it
    is a vector.
    If none of these are defined, HELP confesses defeat.
    You might want to use the abbreviation h which will not appear on
    your history list (or you could overload help itself). Further
    discussion of the HELP command is given in See section The Help Command.



    If word is omitted it is assumed to be HELP.



    You can associate a help string with a vector with the command
    SET HELP.



    See also APROPOS and LIST.


    Histogram

    Syntax: HISTOGRAM WORD1 WORD2 [ IF (expr) ]
    




    HISTOGRAM connects the points in vectors WORD1 and WORD2 as
    a histogram.
    The ith bin of the histogram is taken to run from

    (x[i-1] + x[i])/2 to (x[i] + x[i+1])/2;
    for the case of equally spaced x-values, this reduces
    to saying that the x values are the bin centres.



    If the IF clause is present, only use those points for which expr (see
    the section on vector arithmetic) is true (i.e. non-zero). Only contiguous
    parts of the histogram are connected; if you don't want this behaviour,
    say something like

    set l = (z==1) ? 1 : 0  set x=xx if(l) set yy=y if(l) histogram xx yy
    



    In fact, either or both of the WORDs may be replaced by
    `parenthesised expressions', i.e. expressions in parentheses. For example,

    HISTOGRAM x (2 + y)
    


    to plot x against 2 + y.
    There is a macro barhist for drawing bar charts.
    See Arithmetic for how to convert vectors of data into histograms, and
    SHADE for how to shade them.


    The form with ANGLE is used for drawing a histogram of y against x,
    when the averaging is done in the y- not the x- direction. Compare

    set y = {0 3 1 3 1 0} set x =-0.25,-2.75,-0.5 lim y x
    ERASE box histogram y x
    


    with

    ERASE box histogram angle y x
    


    History

    Syntax: HISTORY [ - ]
    





    List the current commands stored in the buffer. For details on the
    history system, see section Command History.
    With the optional minus sign, the history list is printed
    backwards which is probably what you want if you are thinking of it as
    a set of commands to repeat.
    It's possible to overload list to be a synonym for HISTORY, see
    `overloading' in the index.



    Identification

    Syntax: IDENTIFICATION str
    





    IDENTIFICATION puts the current date and time followed by str outside
    the upper right hand corner of the plot region.
    (Actually, identification is a macro, which RELOCATEs to a point
    above the right-hand axis, and half way between the top axis and the
    top of the page, and then writes a string with a PUTLABEL 4.)
    Note that the variable

    $data_file is set to the name of the current data file, and
    $date always expands to the current date and time.



    If

    Syntax: IF ( expr ) { list } 
            IF ( expr ) { list } ELSE { list } 
    



    If the expr is true (non-zero), then the list of commands
    are executed, otherwise the ELSE clause is executed. For various
    complicated reasons, the ELSEless command must end with a newline
    (or as usual a \n) (see section DO and FOREACH loops, WHILE loops, and IF statements).
    One common use for IF tests is when the expression tests if a variable
    has been defined, e.g.

    IF($?file_name == 0) { DEFINE file_name ? } 
    


    within some macro.



    Note that you can write IF-ELSE IF-ELSE blocks as

    if('Robert' == 'Patricia') {
       echo Something's wrong
    } else { if('Patricia' == 'Ralph') {
       echo Still wrong
    } else {
       echo Go Yankees
    }}
    


    The usual SM logical operators && and || do not
    `short-circuit', unlike e.g. C (Why? Because they are intrinsically
    vector statements, so SM cannot simply evaluate the left hand side
    of the expression and, based on the result, decide to skip the right).
    Fortunately, in a scalar context you can use the AND and OR

    operators instead, and they don't evaluate the right hand side
    if its value is irrelevant. In other words,

    if($?one && $one == 1) { echo One } else { echo No-one }
    


    generates an error if there's no $one variable:

    variable one is not defined
    Syntax error at "="
    if ( 0 & & =
               ^
    
    

    if($?one AND $one == 1) { echo One } else { echo No-one }
    


    is OK.



    There are also commands using IF to define vectors conditionally
    (see SET), and to plot parts of vectors (See CONNECT, HISTOGRAM, POINTS).



    Image

    
    Syntax: IMAGE [n] file
            IMAGE [n] file xmin xmax ymin ymax
            IMAGE [n] file [ * : *]
            IMAGE [n] file [ x1, x1 : *]
            IMAGE [n] file [ * : y0, y1]
            IMAGE [n] file [ x1, x1 : y0, y1]
            IMAGE ( nx , ny )
            IMAGE ( nx , ny ) xmin xmax ymin ymax
            IMAGE CURSOR
            IMAGE CURSOR WORD WORD WORD
            IMAGE DELETE
            IMAGE DEFINE variable value
            WRITE IMAGE WORD
    





    Read an image from file, optionally specifying the range of
    coordinates covered by the data values. If you do not specify them
    they will be taken to be 0 nx-1 0 ny-1 where
    nx and ny are the dimensions of the image. If you specify
    ( nx, ny ) instead of a filename an empty image of the desired
    size will be created (see section Two-Dimensional Graphics).



    If you specify n the n'th IMAGE extension of a fits file
    will be read; the primary data unit (i.e. the start of the file)
    is n == 0.



    If you want to read part of an image you can specify the desired part
    using [ ... : ... ]; (n.b. those [] are part of the command you type,
    not optional parameters). If you want the whole range use *, otherwise
    a pair of 0-indexed integers. In other words,

    IMAGE file
    and
    IMAGE file [ * : * ]
    


    are identical; you can read only the first 100 elements of the first
    row of an image into a vector with

    
    IMAGE file [ 0,99 : 0,0]  SET x=IMAGE[*,*]
    


    IMAGE CURSOR is identical to the CURSOR command (see section Cursor),
    except that value of the image under
    the cursor is returned in addition to the position; IMAGE CURSOR WORD WORD WORD
    is equivalent to CURSOR WORD WORD, but it also generates a vector of
    image intensities.



    IMAGE DELETE will forget the current image and levels.



    The file format is specified using a `filecap' file, similar to
    `graphcap',
    and the entry to use in this file is given by the variable file_type

    (see section Two-Dimensional Graphics).
    The file is unformatted, and should start with two integers giving the
    dimensions of the data
    array, followed by the data values written row by row.



    The current entries in `filecap' support files written from C,
    or from fortran in one of a variety of ways.
    For C programmers, DEFINE file_type C, the file should be written with
    open/write/close.
    For Fortran, there are a variety of options depending on operating systems
    and the details of how the file was opened. Under Unix, simply DEFINE
    file_type unix. Under VMS you have a choice. You can either create a
    variable record type file (recordtype='variable' in the OPEN

    statement) and choose file_type vms_var,
    or set recordtype='fixed' choose recl to be the x-dimension
    of the array and define file_type to be vms_fixed. You must set
    recordtype in one of these two ways.
    By default, data is taken to be real (float in C), but this can be overridden
    in the filecap entry for a file type. There is also an entry for FITS files


    (FITS is the `standard' image transport format for astronomical images).
    If you want to use a different
    file type you'll have to learn about `filecap'
    (see section Two-Dimensional Graphics),
    or else see your local SM Guru.



    So under VMS either your code should look like (file_type = vms_var)

            integer i,j
            real arr(100,10)
    c
            open(2,file=filename,form='unformatted',recordtype='variable')
            i = 100
            j = 10
    c now write your data into arr
            write(2) i,j
            write(2) arr
            end
    
    


    or, with file_type = vms_fixed,

            integer i,j
            real arr(100,10)
    c
            open(2,file=filename,form='unformatted',recl=100,recordtype='fixed')
            i = 100
            j = 10
    c write your data into arr here
            write(2) i,j
            do 1 j=1,10
               write(2) (arr(i,j),i=1,100)
    1       continue
            end
    


    Under Unix, either of these programme fragments would work after omitting
    the record information from the open statement.



    See section Set for an example of creating an image from scratch or a vector.



    If you have an image defined (using the IMAGE command), you can extract
    a cross-section using the SET name = IMAGE ( expr , expr ) command. The
    two expressions give the (x,y) coordinates where you want the image to be
    sampled. For example,

    SET x=0,1,.01 SET z=IMAGE(x,0.5)
    


    will extract a horizontal cross section through an image. You can also use
    IMAGE[expr,expr] to extract values via their indices, where either
    or both
    of the exprs may be * meaning "all values"; this is especially
    useful to those who like to use SM's images as a way of reading binary data.



    An example of creating an image from scratch would be

    image (51,81) 0 1 0 1
    define NX image define NY image
    set ix=0,$NX*$NY-1 set iy=ix 
    set iy=int(iy/$NX) set ix=ix - $NX*iy
    set x=ix/($NX-1) set y=iy/($NY-1)
    set image[ix,iy] = sin(x)*sin(y)
    


    If you have a vector v of size NX*NY, you can say

    
    set image[*,*] = v
    


    to convert it to an image. The data is arranged row-by-row (i.e. in
    the fortran order).



    If you wanted to extract the top row of an image, after

       define NY IMAGE  define NX IMAGE
       set ix=0,$NX-1
    


    you can get the top row with any one of

       set rr=image[ix,$NY-1]
       set rr=image[do(0,$NX-1),$NY-1]
       set rr=image[*,$NY-1]
    
    


    If you want to add 100 to every value of an image, you can say

    set image[*,*] = image[*,*] + 100
    




    It's obviously pretty easy to use SM to manipulate images point-by-point
    in this way.



    You can write the current image to a file using WRITE IMAGE filename.
    Only a small subset of the images that SM can read can be written;
    currently your choices are "C", "CH", and "FITS"; all of these will
    write out floating point values (as images are stored as floats), and
    the FITS writer assumes that you have IEEE arithmetic, in conformity to the
    FITS standard.
    All current image keywords (i.e. those available via DEFINE name IMAGE) are
    written to the FITS header; you can define further keywords with
    IMAGE DEFINE name value.




    Writing and reading images is an space- and time-efficient way of
    saving/rereading vectors in a binary format; if you use the FITS file
    format (i.e. set file_type to FITS) the data will be suitably
    byteswapped if necessary. For example,

            data file.dat
            read { x 1 y 2 z 3 }
            image (3, dimen(x) )
            set image[0,*] = x
            set image[1,*] = y
            set image[2,*] = z
            image define filename file.dat
            define file_type fits
            write image save.fts
    


    and then, in some other SM session:

    
            define file_type fits
            image file.dat
            define filename IMAGE
            set x = image[0,*]
            set y = image[1,*]
            set z = image[2,*]
    


    Note well that defining the image as image(dimen(x), 3) would be
    far less efficient.



    See also ARITHMETIC for how to extract a cross-section into a vector and
    DEFINE for defining a variable from the image header. Images may be displayed
    with CONTOUR or DITHER, and examined with IMAGE CURSOR.



    Key

    Syntax: KEY 
            KEY key string
    




    Define a key to generate a string. This is most often used simply to
    save typing some common command such as edit_hist. With the
    command KEY, you are prompted for the key to define, and the string.
    Because you are not using the history editor when you type the key,
    you can simply hit the key that you want defined, type a space, and
    then type the string terminated by a carriage return. The other form,
    where the whole command appears on one line, is probably more suitable
    for use in a macro such as your private startup macro (see under startup2 in the index). If you try entering it at the keyboard any special
    characters in key, such as ESC, will be interpreted by the
    history editor so you'll probably have to quote the key with

    control-Q or ESC-q. Alternatively you can use ^ and printing
    characters , or octal numbers, to represent the escape characters in
    the same way as for EDIT (see section Edit).
    If key is given as pf# or
    PF# (where # is 1, 2, 3, or 4) it will be interpreted as
    a special function key on your keyboard in a terminal-independent way
    (see the description of termcap (see section Termcap -- A Terminal Database) to see how these keys
    are defined).
    KEY definitions are listed along with
    other key bindings by the LIST EDIT command.



    If the string ends in a \N, it will be executed the moment that
    the key is struck. (Note that this is \N not \n, which would have
    been interpreted as a newline.)



    Only 10 keys can be defined, after that you'll start overwriting
    earlier definitions (this is a result of the way that KEY was implemented;
    if it is a serious nuisance send us mail).



    Label

    Syntax: LABEL str
    



    LABEL writes the string str, which starts one space after LABEL and
    continues to the last non-space character, at the current location (set by
    RELOCATE, etc). After the label is written the current location is on the
    baseline, just to the right of the last character drawn.
    You can of course use quotes to include trailing white space.
    LABEL str is exactly equivalent to PUTLABEL 9 str (see section Putlabel).



    The string's size and angle are determined by EXPAND and
    ANGLE. For more information on fonts and such like, See section Drawing Labels and SM's TeX Emulation.



    Levels

    Syntax: LEVELS WORD
            LEVELS expr
    





    Set the levels for the CONTOUR command to be the values of the
    vector WORD or to the values of the expression.


    Limits

    Syntax: LIMITS WORD WORD
            LIMITS WORD Y1 Y2
            LIMITS X1 X2 WORD
            LIMITS X1 X2 Y1 Y2
    




    LIMITS sets the coordinates of the plot region. All coordinates in RELOCATE,
    DRAW, etc, are referred to these limits. The various forms specify
    explicit limits for the x or y axis (X1 X2 or Y1 Y2), or default
    (specify the name of the vector to be used).


    In fact, either or both of the WORDs may be replaced by
    `parenthesised expressions', i.e. expressions in parentheses. For example,

    LIMITS 0 5 (ln(y))
    


    will scale the y axis according to the logarithm of vector y (but not
    produce a logarithmic axis - see TICKSIZE for this capability).



    The current value of the minimum and maximum values on the x and y axes
    can be obtained with a DEFINE | command, e.g. DEFINE fx1 |.



    If the two limits specified for an axis are the same, the limits for
    that axis will not be changed.



    You can specify that the limits on one or both axes have a desired range
    using the RANGE command. This command affects the performance of the
    LIMITS command. If a non-zero RANGE has been set, LIMITS
    will ensure that the upper and lower limits differ by that amount. (e.g.
    after RANGE 2 0 , LIMITS 0 1 0 1 is equivalent to
    LIMITS -0.5 1.5 0 1 ). If you specify a vector, the range is
    centred on the median value. If you have specified a range, and then
    ask for logarithmic axes with TICKSIZE, you may get complaints that
    logarithmic axes are impossible. Simply unset RANGE, and the problem
    should go away.



    Lines

    Syntax: LINES INTEGER INTEGER
    



    Use only lines INTEGER1 to INTEGER2 from the current data
    file (specified with the DATA command). If VERBOSE is greater than 0, the
    lines actually read
    will be reported. LINES 0 0 will use the entire file, which is also
    the default following a DATA command.
    The variables $_l1 and $_l2 will be set to the first and last
    lines specified.



    List

    Syntax: LIST DEFINE [ begin end ]
            LIST DEFINE |
            LIST DEFINE IMAGE
            LIST DEVICE [ pattern ]
            LIST EDIT
            LIST MACRO [ begin end ]
            LIST SET
            LIST TABLE
    






    list all the currently defined variables (DEFINE) or macros (MACRO),
    optionally only within the range begin - end . If VERBOSE is 0
    macros beginning ## won't be listed. You can list the internal variables
    (i.e. those such as $fx1 that track SM internal variables) with
    LIST DEFINE |, or by setting VERBOSE to be two or more.



    LIST DEFINE IMAGE lists all IMAGE variables (as read from files with
    IMAGE or TABLE, or defined with IMAGE DEFINE name val). FITS keywords
    are omitted if verbose is 0. You can use DEFINE name IMAGE to convert
    these to regular SM variables. The variables listed when verbose
    is 0 are those written to the headers of files written using the
    WRITE IMAGE or WRITE TABLE commands.



    LIST EDIT will list all the keybindings. If VERBOSE is 0 only the keys
    that don't generate themselves are listed (i.e. because A is bound
    to A it isn't listed). If VERBOSE is 1, in addition all non-printing keys
    are listed, and if VERBOSE is 2 or greater all keys are listed. Both the
    EDIT and the KEY bindings are listed.



    LIST DEVICE will list all the devices known to SM. The devices are
    listed with each device on an (indented) line, first the primary name,
    then a list of aliases in parentheses, then a full name. If pattern
    is provided only those lines that match the given pattern will be printed,
    for details on SM's regular expressions See section Apropos. An example would
    be

    LIST DEVICE ^post
    


    to list all devices whose principle name begins `post'.



    LIST SET lists all currently defined vectors. For each vector the name,
    the dimension and the HELP field are given. See SET for how
    to set the latter.


    LIST TABLE lists all columns available in the current TABLE; this currently
    only works for FITS binary tables.



    For a list of the history buffer use HISTORY (macro lis), to list a
    macro use HELP (macro h). It can be useful to overload `list' so
    that it doesn't appear on the history list, and so that `list' by
    itself corresponds to the command HISTORY (this is done for you if you
    use set_overload or put overload in your `.sm'
    file).



    Local

    Syntax: LOCAL DEFINE name value
            DEFINE name LOCAL
            LOCAL set name = expr
            SET name LOCAL
    








    Usually, SM's variables (see section Define) and vectors (see section Set)
    have global scope, meaning that if you define one in a macro it is
    still defined when you return to the command prompt. This is often
    what you want, but not always; for example macros often define scratch
    vectors that must be explicitly deleted before returning. This is
    annoying, but a more serious problem is that two different macros
    can each set a vector called i, but mean different things.



    The solution to this is to make your vectors and variables local to
    a macro, meaning that they are only visible within that macro, and from
    any called from it. This is really a nested scope rather than local,
    but LOCAL is easier to type.
    Such local objects are automatically destroyed when they go out of scope.


    For example, if you define the macro bar as

       macro bar 2 {
          echo $(goo)
          set goo local 
          set goo=$1
          if(goo < $2) {
             bar $(goo+1) $2
          }
          echo $(goo)
       },
    


    the command set goo=0 bar 1 5 will count from 0 to 5 and down again,
    and if you run the macro yar (defined as

    macro yar { set foo local set foo=1\n}) the vector foo will
    not be defined at global scope.



    Note that, as usual, you may have to be a
    little careful to ensure that you don't exit a macro before you expect.
    The symptoms would be that your local variable or vector was already
    destroyed, or that
    it referred to one at less restrictive scope (see section The Command Interpreter).
    The easiest fix is to add a comment line to the end of the macro.




    Location

    Syntax: LOCATION GX1 GX2 GY1 GY2
    





    Set the physical location of the plot. The plot region is the rectangle
    inside the box drawn by BOX. Vectors and points are
    truncated at the bounds of the plot region. LOCATION specifies (in device
    coordinates) where the plot region is located. LOCATION can be used to make
    an arbitrary size and shape plot, providing that you want it rectangular.



    Because all devices have the same coordinate system in SM
    (0-32767), this command is considerably more useful than it used to
    be. The default LOCATION is 3500 31000 3500 31000. You can get at the
    current values of GX1 etc. using the DEFINE | command.



    While you are using WINDOW (see section Window), LOCATION commands have no effect.
    SM remembers them, however, and obeys the most recent one when you are
    finished with WINDOW.



    See the RELOCATE ( x y ) command to draw labels outside the plot region,
    and DRAW ( x y ) to draw lines there.


    If you want to increase the x-location by 500 (say), you can say:

            LOCATION $($gx1 + 500) $gx2 $gy1 $gy2
    


    This is sometimes useful to make room for an axis label; if your verbosity
    is 1 or higher you'll be advised of the appropriate displacement.



    Logical

    Syntax: Logical Operators
    



    The following logical operators are allowed on vectors and scalars in
    SM, where non-zero means true:

    Unary:
    
    !expr           Logical Complement    
    
    Binary:
    
    expr == expr    Equal to             expr != expr    Not equal
    expr < expr     Less than            expr <= expr    Less than or equal
    expr > expr     Greater than         expr >= expr    Greater than or equal
    expr && expr    Logical and          expr || expr    Logical or
    
    


    Only !, ==, and != are allowed for string valued vectors.
    All arithmetic vectors test unequal to all string-valued vectors. Invalid
    floating point values (those which print with a *) always compare
    non-equal, even to themselves (this is the same behaviour as IEEE's NaNs).




    For string vectors, there are three cases to consider:
    vstr1 == vstr2 generates a vector of the same length as
    vstr1 (with must be the
    same length as vstr2) by comparing the two vectors element by element;
    'str1' == vstr
    generates a vector of the same length as vstr

    by comparing each element of the vector vstr to the string str1;
    and
    'str1' == 'str2'
    which returns a scalar by comparing the strings str1 and str2
    (so it's false in this example).



    As in C, == has a higher precedence than &&, which in turn has
    higher precedence than ||.
    As noted in See section If, && and || evaluate both the left- and
    right- hand expressions. If this is a problem, you can use AND and

    OR instead.



    Note that there is also a ternary operator, (expr1) ? expr2 : expr3
    which has the value expr2 if expr1 is true, and expr3

    if it is false.



    See `arithmetic' for the arithmetical operators See section Arithmetic.
    You can test to see if a variable is defined by looking at the value
    of $?var (see section Define).



    Ltype

    Syntax: LTYPE INTEGER
            LTYPE ERASE
            LTYPE EXPAND number
    
    








    All lines except for those making up axes and characters are drawn
    with line type INTEGER, meaning:

    0       solid                           1       dot
    2       short dash                      3       long dash
    4       dot - short dash                5       dot - long dash
    6       short dash - long dash                  
    
    


    the default is a solid line, LTYPE 0. The current value of LTYPE
    is available as an internal variable (e.g. DEFINE ltype |)


    LTYPE ERASE and will erase any lines
    that are redrawn (e.g. LTYPE 0 BOX LTYPE ERASE BOX will first draw a
    box, and then erase it). Not all devices can support erasing
    individual lines, if yours doesn't you'll have to ERASE the whole
    screen. A convenient way to use LTYPE ERASE is the undo macro.
    (in fact, LTYPEs 10 and 11 are used to implement LTYPE ERASE,
    LTYPE 10 to start erasing, LTYPE 11 to notify a device that you've finished
    doing so).


    LTYPE EXPAND makes all dots, dashes, and spaces in the chosen ltype
    larger (or smaller) by the value specified.



    Lweight

    Syntax: LWEIGHT number
    





    Set all lines to have a weight of number, where the bigger the blacker.
    Generally, an lweight of 0 is taken to be the hardware's preferred width.
    The current value of LWEIGHT is available as an internal variable
    (e.g. DEFINE lweight |)



    Macro

    Syntax: MACRO EDIT name
            MACRO LIST [begin end ]
            MACRO name [ narg ] { body }
            MACRO name [ narg ] < body >
            MACRO name DELETE
            MACRO name #1 #2
            MACRO READ file
            MACRO WRITE file
            MACRO DELETE file
            MACRO WRITE name [ + ] file
    





    MACRO EDIT name allows you to edit a macro. All the commands available to
    the history editor area available (including the ^ history), except
    that control-M inserts
    a line before the cursor, control-N and control-P get the next and
    previous lines respectively, and control-V and ESC-v move forwards and
    backwards 5 lines at a time.
    To exit use control-X

    (or whatever you have bound to exit_editor).
    The macro need not exist, and both its name and number of arguments can be
    changed by editing the zeroth line of the macro (control-P from the
    first line. If this line is corrupted, or deleted, no changes are made to the
    macro when you exit. If the number of arguments is negative, the macro will be
    deleted when you exit.) You may prefer to use the macro ed instead of
    MACRO EDIT, as it doesn't appear on the history list and, if invoked
    without a macro name will edit the macro that you edited last. Incidently,
    hm (`help macro') will list the last macro that you edited with ed.
    The keybindings may be changed with READ EDIT.



    LIST MACRO lists all currently defined macros, or all those which are
    between begin and end alphabetically (asciily). If VERBOSE is
    0, macros starting with ## are not listed.



    MACRO name [narg] { body } defines name to be body,
    where name is a
    single word, and body may be anything (most users need not
    worry about the form in angle brackets; it is occasionally useful when
    writing clever macros). A macro is invoked by
    typing its name.
    The optional nargs is the number of arguments the macro expects,
    default 0.



    If the macro's body is defined to be delete, the macro is deleted.
    MACRO name DELETE also deletes a macro.



    Arguments are referred to as $1, $2, ... $n, up to a maximum of $9.
    $0 gives the name of the macro. If the number of arguments has
    more than one digit (e.g. 03 or 12), the macro is taken to have a variable
    number of arguments, between the `tens' digit and the `units' digit.
    For example, 12 means 1 or 2 arguments, 39 means between
    3 and 9 arguments, and 02 means 0, 1, or 2. Confused? HELP

    will tell you what SM knows about a macro's arguments.
    There's one problem here; if you say

    MACRO woosie 01 {
       if($?1) {
          echo An argument: $1
       } else {
          echo No arguments
       }
    }
    


    SM will interpret that 01 as the integer 1 before the macro's
    defined, so that's equivalent to MACRO woosie 1 { ... }. So you
    cleverly say MACRO woosie "01" { ... }; but that won't work either
    as the closing " is seen before the 01's parsed; you have to say

    MACRO woosie "01 " { ... } -- and that does work.
    (21) You don't
    have to go through any such contortions in files read by MACRO READ,
    but they have their own problems.



    If the number
    declared is greater than 99 the last argument will extend to the end
    of the line, and may consist of many words. When called, all the arguments
    must appear on the same line as the macro itself. This line may, as
    usual, be ended with an explicit \n. The macro can determine whether
    it has been supplied a given argument by using the $? construction
    (see DEFINE). It is also possible to change the values of arguments
    using DEFINE just as usual, and even to DEFINE arguments that you
    didn't declare. These are temporary variables, local to the macro, and
    will disappear when you exit the macro.



    Macros must end in space or newline, and if they don't SM will silently
    add one (why? to prevent the macro stack being popped prematurely
    see section The Command Interpreter). If you want to defeat this, end your
    macro with an explicit #, e.g. macro echo {WRITE STANDARD#}; a
    slightly less efficient
    alternative would be macro echo 111 {WRITE STANDARD $1}.



    MACRO name #1 #2 defines macro name to consist of lines #1 -- #2
    of the history buffer.
    If #1 or #2 is negative it is interpreted
    relative to the current command, so saying MACRO last2 -1 -2

    will define a macro last2 consisting of the last 2 commands issued.



    MACRO READ file reads the macros in file and defines them.
    See RESTORE for how to also restore the history buffer from macro all.


    MACRO DELETE file has the effect of deleting all macros defined in
    file.



    MACRO WRITE file writes all currently defined macros to file in
    alphabetical order.
    If the file exists, and $noclobber is defined, SM will refuse to
    overwrite the file. You can set noclobber by specifying it in
    your `.sm' file.



    MACRO WRITE name [ + ] file writes the macro name to file.
    If the + is specified, or the file is the
    same as for the previous use of this command, the macro is written to the
    bottom of the file, otherwise the file is created.
    If the file exists and you aren't simply appending, and $noclobber is
    defined, SM will refuse to overwrite the file.
    You can set noclobber by specifying it in your `.sm' file.



    Meta

    Syntax: DEVICE META WORD
            DEVICE META CLOSE
            META READ WORD
    






    If you open the special device called META it doesn't close the current
    device, merely intercepts plotting commands and stores them away as well
    as executing them immediately. This continues until you issue a
    CLOSE command.


    The command META READ reads a metafile and executes it on the current
    device. So to make hardcopy of a plot you could say something like:

    device x11
    device meta metafile.dat
    my_cunning_macro
    more_brilliance
    device meta close
    


    after which (maybe after exiting SM and restarting it), you could say:

    device postscript
    meta read metafile.dat
    device 0
    


    to make a hardcopy.



    It is safe to concatenate metafiles together, if the fancy takes you.



    Because of the way that SM interrogates devices about their abilities,
    while using META all ltypes, lweights, and fonts will be emulated in
    software (this guarantees that the device you playback on will be able
    to handle the code). If the current device can handle dots (i.e.
    PTYPE 0 0) then META will attempt to use them too, but if
    it can't then META will be reduced to faking them. This could
    be a serious problem, so good luck. Metafiles do not support colour,
    again due to the impossibility of knowing if they will have the same
    behaviour as the original device.



    Minmax

    Syntax: MINMAX min max
    



    Set variables min and max to the the maximum and minimum
    values of an image
    read by the IMAGE command. Only that portion of the image within
    the current LIMITS is examined.
    This may be useful for setting contour levels,
    or doing a halftone plot (see the macro greyscale).



    For example, the commands:

    MINMAX min max
    SET levs = $min,$max,($max-$min)/9
    LEVELS levs
    

    will choose a set of 10 levels which cover the complete range of the data.


    Notation

    Syntax: NOTATION XLO XHI YLO YHI
    




    Set axis label format (exponential or floating). By default, all numbers
    between 1e-4 and 1e4 are written as floating point numbers, and all numbers
    outside this range are written with an exponent. This corresponds to a
    NOTATION -4 4 -4 4 command.



    If you set XLO=XHI and/or YLO=YHI,
    all values on that axis will be plotted using exponents (including 1); as
    a special case if both XLO and XHI are 0 NOTATION will
    be reset for this axis.



    If you want your positive and negative exponents to line up
    define the SM variable line_up_exponents; if it's 1 they'll
    be padded with a space, if 2 or more, with a +
    (you can do this in your `.sm' file).



    Or

    Syntax: OR
    





    In a scalar context, you can use OR instead of ||. The difference
    is that OR doesn't evaluate the right-hand-side of the expression if
    the left-hand-side is true; See section If, for examples.



    Overload

    Syntax: OVERLOAD keyword INTEGER
    




    Allow "keyword" (in lowercase) to be used as a macro name if
    integer is non-zero. For example,

    overload set 1 overload define 1
    macro set { DEFINE } macro define { SET }
    


    would interchange the
    meanings of the SET and DEFINE commands. The uppercase forms
    of the keywords retain their usual meanings. overload set 0
    would reinstate the usual meaning of set. You may be surprised by the
    effects of overloading certain keywords. For example, if you overload
    help to mean DELETE HISTORY HELP, then set help vec
    help_string
    won't work (you'd have to say set HELP vec ...).


    This command is intended to be used for changing the default action of
    commands, rather than for a wholesale renaming of keywords! A more practical
    example than the above would be

    overload erase 1 macro erase { del1 ERASE }
    


    to prevent erase commands from appearing on the history list. See the
    macro set_overload for a set of definitions like this. It can
    be automatically executed by including an "overload" line on your
    `.sm' file.



    Page

    Syntax: PAGE 
    



    PAGE starts a new page for a hardcopy plot (n.b. the device driver for
    raster plots is unable to support multiple page plots).



    On window systems (X11, SunView) page will raise the window and refresh
    it if necessary.



    Points

    Syntax: POINTS WORD1 WORD2 [ IF (expr) ]
    
    






    POINTS makes points of the current style (PTYPE), linetype (LTYPE),
    colour (CTYPE), size (EXPAND), and rotation (ANGLE) at the points in
    vectors WORD1 and WORD2.
    If the IF clause is present, only use those points for which expr (see
    the section on vector arithmetic) is non-zero.
    In fact, either or both of the WORDs may be replaced by
    `parenthesised expressions', i.e. expressions in parentheses. For example,

    POINTS x (lg(y))
    


    to plot x against the logarithm of y.



    In case you ever need to know, the distance from the centre of a point
    to a corner is 128 screen units when unexpanded, if the ASPECT
    (see section Aspect) ratio is unity.



    Print

    Syntax: PRINT [+] [ file ] [ 'format' ] { list }
            PRINT [+] [ file ] [ 'format' ] < list >
    
    







    Print the vectors specified by list to file, if file is
    absent, print to the terminal (the output is paged, sort of).
    The name of each vector is printed at the head of the
    appropriate column. If the output is going to a file, each line of the
    header starts with a `#', so the file can be read without using the
    LINES command.



    The header is not printed if the variable
    print_noheader is defined and non-zero. For example, I have a macro

    p       111     ## print a vector or expression. E.g. "p x" or "p sin(x)"
                    local define print_noheader 1
                    local set foo=$1
                    if(whatis(foo) & 2**5) {
                       print '%g ' { foo }
                    } else {
                       print '%s ' { foo }
                    }
                    #
    


    to print vectors on a single line.
    In addition, no header is printed if you are not actually printing any vectors,
    in this case no newline is appended to the string. This provides a way of
    controlling string output, and suppressing newlines, e.g.
    PRINT 'S' {} PRINT 'M\n' {}. You probably will usually want
    to use WRITE STANDARD instead (see section Write).



    With the optional `+' the vectors are appended to the file, otherwise
    it is overwritten unless $noclobber is defined, in which case
    SM will refuse to touch the file. You can set noclobber by
    specifying it in your `.sm' file.



    The optional format string is of the type accepted by the C function
    `printf', and you should see a book on C (or maybe the online system
    manual or help command) for more details. Basically, the format string
    is copied to the file with format specifiers beginning with %

    signs replaced by the numbers that you want printed. The format
    specifiers to use are the floating point ones, %e
    (exponential), %f (floating point), and %g (computer's
    choice), d, o, x for printing numbers as integers
    (the latter two are octal and hexadecimal), or %s for strings.
    Fields are right justified by default, you
    can insert a - just after the % to left justify them. A

    % may be written as %%, and a tab as \t. Lines
    are not terminated by a newline by default, you have to write
    them explicitly as \n.



    For example,

    
    SET x=1,10 SET y=x**2
    PRINT file '%10f (%10.2e)\n' { x y }
    


    will produce

    #........x............y
    #
    ..1.000000.(..1.00e+00)
    ..2.000000.(..4.00e+00)
    ..3.000000.(..9.00e+00)
    (etc.)
    


    where I have replaced each space by a . for clarity. If you say

    PRINT '%g ' { x }
    


    you will get

    ..........x
    
    1.2.3.4.5.6.7.8.9.10.
    


    If you want very long output lines you'll run into one of SM's internal
    limits; the maximum length of a string (currently 160 characters).
    You might try to work around this
    by putting part of the formatted output into string vectors and then using
    a %s format to write it out; such an approach can be
    made to work, for example instead of

    print file 'Date: %2d %2d %4d\n' { dd mm yy }
    


    you can write

    set date = sprintf('Date: %2d',dd) + \
               sprintf(' %2d',mm) + \
               sprintf(' %4d',yy)
    print file '%s\n' { date }
    
    


    If you think that this is a hack I rather agree with you, but it does
    permit formatted output of up to 400 characters.



    Prompt

    Syntax: PROMPT new_prompt
    




    The current prompt is replaced by new_prompt; the default is

    :. Any occurrences of
    the character `*' are taken as instructions to ring the terminal bell.
    When you start SM your prompt is set to the value of the entry
    prompt in your `.sm' file (if you have one).



    If you enter a partial command (e.g. macro foo { or echo ABC\)
    SM switches to a different prompt. By default this is >>, but if you
    define the variable prompt2 that will be used instead. You can
    set prompt2 in your `.sm' file.



    Ptype

    Syntax: PTYPE n s
            PTYPE WORD
            PTYPE ( expr )
            PTYPE { list }
    




    PTYPE n s causes points to be drawn as n sided polygons of a
    style s, where s refers to:

    0

    open
    1

    skeletal (center connected to vertices)
    2

    starred
    3

    solid


    For example, PTYPE 1 1 (or PTYPE 0 0) makes points appear as
    dots, PTYPE 4 1 (the default) makes
    (diagonal) crosses, and PTYPE 6 3 makes filled hexagons.
    Points made up of lines (types 0, 1, and 2)
    are drawn using the current LTYPE.



    When possible PTYPE 0 0 will draw the smallest possible dots that
    the device is capable of; these may or may not be different from
    PTYPE 1 1.



    The current value of PTYPE is available as an internal variable (e.g.
    DEFINE ptype |)


    PTYPE WORD or PTYPE ( expr ) use vector WORD or the
    expression expr as its source of n and
    s, ( so you may define different point types for each point) except
    that the
    numbers are contracted together. If the entry has a fractional part, it is
    treated as an expansion factor, relative to the current expansion
    (no fractional part means default expansion); so if

    n is a vector giving the desired number of sides for a set of points,
    s is a vector giving the desired types, and e is a vector
    giving the desired relative sizes (0 <= e < 1), you'd want to say
    PTYPE (10*n+s+e).
    For example, an an entry of 103.5 in WORD is the same as PTYPE 10 3,
    EXPAND 0.5, but if you now say EXPAND 2 the net expansion will be unity.
    It's much easier to use a vector of
    expansions directly to the EXPAND command, but fractional ptypes are
    preserved for backwards compatibility.

    N.b. due to a bug in X10R4 for the Sun,
    PTYPE n 3 does not work for dev xwindows on a sun
    .
    If more points are specified than
    the dimension of expr, the first element will be used for the excess.



    If WORD is a string-valued vector, its elements are used to
    label the points of the graph. They are drawn at the current expand
    and angle (vector-valued EXPANDs and ANGLEs are ignored), and in the
    current default font. For TeX-string users this can be specified
    with the variable default_font, which can either simply be defined,
    or set in your `.sm' file.




    PTYPE { list } defines the symbol to use with the POINTS
    command to be some creation of the user.
    The list consists of a set of c x y where c is a letter,
    and x

    and y are integers. If c is `m' or `r' (move or relocate)
    the plot pointer is moved to the point (x,y), if it is `d' (draw) or absent
    a line is drawn from the current position to the point (x,y). The coordinates
    are measured relative to the current point being plotted, and are
    measured in screen coordinates (i.e. 0-32767). Both EXPAND and ANGLE
    are applied to the (x,y) values as usual.



    As an example the command

    PTYPE { m 0 500 500 0 0 -500 -500 0 0 500 } 
    


    will define the marker to be a diamond, something like:

    
                      /\
                     /  \
                     \  /
                      \/
    


    (but with unbroken lines). As a more useful example, there is
    a macro upper which defines a variable $upper to draw an upper limit
    sign, used as

    PTYPE $upper
    


    (if ANGLE were 180, they'd be lower limits).



    Putlabel

    Syntax: PUTLABEL INTEGER str
    




    PUTLABEL writes a label at the current location with rotation and
    size specified by ANGLE and EXPAND (exactly like LABEL). The label
    is centered with respect to the current location according to the
    argument INTEGER which can be 1 - 9 meaning that the label is:

                            left    centre  right
            above           7       8       9
            centered        4       5       6
            below           1       2       3
    
    


    (cf. a vt100 keyboard)
    To be a little more precise, `above' means that the string's baseline
    (the bottom of characters such as `a' that have no descender) is at the
    level of the current point, while `below' means that the top of the tallest
    character in the string is level with the current point. If you don't like
    this neglect of descenders, try

    MACRO myputl 102 {label \raise\advance\depth{$2}by100{}\n putlabel $1 $2}
    myputl 7 This is a Label
    


    (You can then say overload putlabel 1 macro putlabel {myputl}
    if the mood takes you).
    After the label is written the current location is on the
    baseline, just to the right of the last character drawn.
    If INTEGER is 0 the string isn't actually drawn,
    but the string's dimensions are calculated (and are available as
    $swidth, $sheight, and $sdepth), and any
    TeX definitions are remembered. If PUTLABEL 5 isn't quite what you want
    (as it centres vertically as well as horizontally), try

    LABEL \centre{H_\alpha} instead.



    See section Drawing Labels and SM's TeX Emulation, for a description of how
    to enter a label with funny characters, sub- and super-scripts, and so forth.



    If EXPAND is set to exactly 1, and ANGLE is exactly 0, then SM
    will use hardware fonts, when available, in writing labels. This is faster,
    but if you don't like it say "EXPAND 1.00001",
    or use a \r explicitly to select the roman font. Or ask your
    SM Guru to edit the `graphcap' file to stop your printer
    from ever using hardware fonts (or read the discussion under LABEL).



    Quit

    Syntax: QUIT 
    




    Quits the programme entirely.



    The macro `q' is defined as something like

    DELETE HISTORY DEFINE 1 0     # default value
    DEFINE 1 ? { Are you sure? Enter 1 to really quit }
    IF($1) { QUIT } 
    


    so you won't quit accidently, and the QUIT won't appear
    in the history file. This is an obvious candidate for overloading.



    Range

    
    Syntax: RANGE number_x number_y
    


    If number is non-zero, set the range on the x or y axis to be number,
    so LIMITS will choose two values that differ by number. Nothing will
    happen until you issue a LIMITS command.



    For instance, if you wanted to ensure that the y axis of a logarithmic plot
    spans exactly two decades the commands RANGE 0 2 LIMITS x y would
    choose suitable y limits, with actual values appropriate for the y

    vector. If the `natural' limits are less then range then the limits
    will be chosen about the centre of that interval, otherwise they'll be
    centred on the median value of the data.



    Read

    Syntax: READ WORD INTEGER
            READ [ ! ] { WORD INTEGER WORD INTEGER ... }
            READ [ ! ] { ... WORD range ... }
            READ ROW WORD INTEGER
            READ [ ! ] 'format' { WORD WORD ... }
            READ EDIT WORD
            READ OLD WORD WORD
            META READ WORD WORD
    




    READ WORD INTEGER reads a column of data from the file specified
    by the DATA command, using the lines specified by LINES. Columns may
    be separated by white space (blanks or tabs) or by a comma, or by some
    combination of the two. It's OK if some of the columns contain text,
    providing that you don't try to read them. You can read text columns
    into string vectors, as described in the next paragraph.
    The data is
    read into the vector WORD, which will be created, from column

    INTEGER. Any field beginning with a * is taken to be `empty',
    and is assigned the value 1.001e36. Any line beginning with a
    # is skipped over (and printed if VERBOSE is greater than 1), any line
    beginning with a ! is skipped and always written to the terminal.
    Long (logical) lines may be spread over
    several (physical) lines by ending the line with a `\'; no line may
    exceed a total of 1500 characters. If you use continuation lines, note
    that SM's line numbers (for example, as set with the LINES command)
    apply to logical not physical lines; a continued line counts
    as only one line.




    You can optionally specify a type of vector by adding a suffix onto the
    integer; `.f' (the default) or `.g' means floating point,
    `.d', `.o', `.i', or `.x'
    means integer, `.s' means string-valued.
    String valued vectors can be used as input to PTYPE commands, or
    simply for reading columns from data files that you want to PRINT.




    READ { WORD INTEGER WORD INTEGER ... } is the same as repeating
    READ WORD INTEGER for each vector, but more efficient as it only has to
    read the file once.

    READ { x 1 s 5.s y 2.f z 3.i }
    


    will read columns 1 and 2 into floating point vectors x and y,
    column 3 into an integer-valued vector z,
    and column 5 into string-valued vector s. As noted below, you can
    omit the INTEGERs by specifying an empty format: READ " { x y.d } (those
    are two single quotes).



    Usually
    SM stops reading at the first invalid line, but if you say READ ! all
    the lines specified with LINES (or the entire file) are read.
    Missing numerical fields are set to be invalid (i.e. they are treated as *);
    missing string values are left blank. This is probably most useful with the

    %n format specifier.



    If INTEGER is invalid (<= 0), the contents of the file are written
    to the standard output. READ ROW is very similar, but the values
    are read from row INTEGER of the file (any LINES command is ignored).
    The same type qualifiers are allowed as for reading columns. There is no
    limit to the number of elements in the vector, except that implied by
    the maximum length of a line. You cannot specify a range of columns to
    read with READ ROW, but try

    SET i=2,5
    READ ROW x 1
    SET x=x[i]
    


    If the first field is a string, you can say READ ROW s 1.s SET x=ATOF(s[i]).




    If your data is in a number of columns (e.g. you have written it out to a file
    ten values to a line) you can specify a range of columns, for example

    READ { x 1-4 y 5 z 6-10 }.
    


    You can only use ranges for numerical vectors, and only with the list form
    of READ. Ranges won't work if
    there is a short line at the end, but you can still say something like

    LINES 0 100
    READ { x 1-4 }
    READ ROW _x 101
    SET x=x CONCAT _x
    


    which will be almost as efficient if you have defined $save_read_ptr.





    In order to speed up multiple reads of the same file, SM usually remembers
    where it got to in a file; this is disabled if you undefine the variable
    $save_read_ptr (which can be done in your `.sm' file by setting
    it to 0). The remembered position is forgotten every time that you issue a
    DATA command,
    or try to re-read part of the file. You can get into trouble if you read
    part of a file, modify the file without reissuing a DATA command,
    and then read some more, but in normal
    usage it should be safe to leave saving the read pointer enabled.



    Instead of using simple column-oriented input
    it is possible to specify a format similar to those used by C's scanf
    functions (Fortran formats are not supported); if you don't know C
    then most of what you need to know is that characters in the input
    must match those in the input file, except that items to be read are specified
    with format strings that start %. For example, a format
    abc%f:%f expects the input to consist of `abc' then two floating point
    numbers separated by a colon.
    If the % is followed by a *
    the field is read but isn't assigned to a vector.
    You can specify a newline as \n or a tab as \t.



    As a further example, if your data file has lines like

            1:12:30  -45:30:11
    


    you could read it with

            read '%d:%d:%d %f:%f:%f' { hr min sec deg dmin dsec }.
    


    The type of the vector is deduced from the format string; you can't
    use .f or .s in the vector list (why would you want
    to specify a type twice?).



    As a special case, of you specify an empty format (") the named vectors
    are read as floats from the first n columns of the file, so

    READ " { x y z }
    


    is equivalent to

    READ { x 1.f y 1.f z 3.f }
    


    or simply

    READ { x 1 y 1 z 3 }
    
    


    You can use the usual qualifiers, e.g.

    READ " { x y z flags.x }
    


    and omit columns entirely by replacing the vector's name with .:

    READ " { x . z }
    

    I said that the %-formats were `similar' to scanf's; they differ
    in the way that they treat field widths and white space. If you don't
    specify a width at all SM follows the usual C behaviour of skipping
    white space between items; if you do specify a field width no space is
    skipped over before the field begins. You can always explicitly skip
    spaces with a %*[ ] format. The %n format returns the number
    of fields matched rather than the number of characters.



    The supported format letters are d, e, f, g,

    o, n, s, x, and [, their meanings are:


    %d

    Read an integer into a floating vector (`d' stands for `decimal'). If a
    field width is specified trailing spaces are treated as spaces not zeros
    -- this isn't fortran you know. The field " 1234 " (i.e. a
    field width of 6, %6d) has the value 1234 not 12340.

    %e

    %g

    Read a floating point number with or without an exponent into a floating
    vector. As for %d, trailing spaces in a fixed-width field are treated
    as spaces not zeros.

    %f

    Read a floating point number without an exponent into a floating vector.
    As for %d, trailing spaces in a fixed-width field are treated
    as spaces not zeros.

    %n


    Return the number of fields that are already correctly
    matched in the current line; this is only useful in conjunction with
    READ !.

    %o

    Like %d, but the number's taken to be octal.

    %s

    Read a string into a string-valued vector. If a field width is specified
    the entire field is read spaces and all; if there is no width initial spaces
    are skipped as usual and the string is terminated by the first white
    space character.

    %x

    Like %d, but the number's taken to be in hex.

    %[...]

    Read a string consisting of the characters ... into a string valued
    vector. You can specify a range as a-z so %[a-zABC0-9] would
    read a string consisting of any lower case character or digit, or one
    of A, B, or C.
    If the first character is ^, read any characters except those
    specified (e.g. %[^abc] reads anything but
    the letters a, b, or c). If a field width is specified characters that
    don't match those specified at the end of the field are ignored.

    %%

    Not a conversion format, but a literal %.


    READ EDIT WORD reads a new set of keybindings from the file WORD.
    The format and syntax are given under History (see section History) in the
    introduction.



    READ OLD WORD1 WORD2 defines macro WORD1 to be the the
    contents of file WORD2. This is provided for compatibility with
    Mongo (see section Tips for Mongo Users) and the read_old macro. You no longer
    need use read_old to read SM history files, use RESTORE
    instead.



    If VERBOSE (see section Verbose) is greater than 0, the lines actually
    read will be reported.



    META READ WORD reads a metafile, as produced with the pseudo-device
    META, and executes the enclosed commands on the current device.



    Relocate

    Syntax: RELOCATE X Y
            RELOCATE ( X Y )
    




    The first form sets the current position to (X,Y) in user
    coordinates without drawing a line. The second (with parentheses) sets
    the position in `screen' coordinates, i.e. 0-32767. The current
    position is used by the DRAW, LABEL, and PUTLABEL commands.



    There are a couple of pairs of internal variables ($uxp,$uyp)

    and ($xp,$yp) that give the current position of the plot pointer,
    either in user or screen coordinates.


    Restore

    Syntax: RESTORE [ filename ]
    


    Restore all the current macros, variables, and vectors from file

    filename
    (if omitted the default is to use the value of save_file in
    your `.sm' file, or failing that `sm.dmp'). In
    addition, the current history buffer
    is replaced by the macro all if defined in the RESTOREd file.



    The file should have been written by the SAVE
    command, and RESTORE will treat any other file type as if it were a
    SM history file and add its commands to the end of the
    current history list.



    If VERBOSE (see section Verbose) is greater than 0, some extra information
    is printed.


    Return

    Syntax: RETURN 
    




    Return from the current macro, which includes breaking out of
    DO and FOREACH loops. If you are not executing a macro,
    simply return
    to the prompt (this is more or less equivalent to typing control-C).



    A RETURN can be useful while playing with fiddling with data
    interactively. For example, if you want to playback
    a set of commands, but then do other things when the plot has
    appeared, you could put a RETURN after the desired part of the
    playback buffer. (This doesn't work quite the way that you might
    naively think. Playback works by defining a macro all from
    the history list, and then executing it. The RETURN is actually returning
    from this macro, rather than directly from the command list,
    but the effect is the same. If RETURN always returned
    directly to the prompt, macros such as hcopy wouldn't work.)



    If VERBOSE is 2 or more, the name of the
    macro being returned from is output.



    If the very last command in a macro is RETURN then the RETURN
    will take place, not from the desired macro, but from where the macro
    was called from. You can work around this by putting
    a space after the RETURN, or simply omitting it as it isn't doing anything
    anyway. If a RETURN comes last on a history list, this problem will
    lead to macros such as hcopy not working correctly
    .



    Save

    Syntax: SAVE [ filename  ]
    




    Save some or all of the current macros, variables, and vectors
    in file filename
    (if omitted the default is to use the value of save_file in your
    `.sm'

    file, or failing that `sm.dmp'). The current history buffer may also
    be saved, as the macro all.



    You are prompted for whether you want to save
    variables, vectors, and macros (which includes all, the current
    playback buffer). Macros beginning
    ## are not saved, as they are assumed to be system macros.
    Variables and vectors whose names start with a `_' are assumed to be
    temporaries, and are not saved either.



    The opposite to SAVE is RESTORE (see section Restore).
    You may want to use the MACRO
    DELETE WORD command to undefine macros from e.g. the `utils' macro file.
    See, for example, the macro sav (which can be overloaded).



    If VERBOSE (see section Verbose) is greater than 0, some extra information
    is printed.



    Set

    Syntax: SET name = expr
            LOCAL SET name = ...
            SET name = { expr }
            SET name = < expr >
            SET name = expr IF ( expr )
            SET name = expr1, expr2 [, expr3 ]
            SET name = expr1 ? expr2 : expr3
            SET name LOCAL
            SET DIMEN ( name ) = INTEGER
            SET name = WORD ( [ WORD [ , WORD ... ] ] )
            SET name [ expr ] = expr
            SET name [ expr, expr ] = expr
            SET IMAGE[expr, expr] = expr
            SET HELP WORD [ rest ]
            SET RANDOM s_expr
    









    Conduct various operations on vectors of data.
    The simplest, SET name = expr sets vector name
    to be equal to the expression expr.
    If the IF clause is present, name will only contain
    those elements of expr for which it is true (non-zero).
    A special case of an expression is simply a list of values within braces (or
    angle brackets).(22)

    For string-valued vectors, the
    only allowable expressions are a string-valued vector, the
    CONCATenation of two string vectors, the addition (i.e. element-by-element
    concatenation), or a string in single quotes
    (e.g. SET s='Hello, World' or
    SET ss='n_{' + < e cl co g > + '}').



    Within a macro,
    any of these commands that set an entire vector may be preceded by the
    word LOCAL. This ensures that the vector name
    is only visible within that macro, and any called from it (see section Local).
    Future references to the name automatically refer to the local vector,
    so only the first occurrence need be preceeded by LOCAL.
    Such local vectors are automatically destroyed when they go out of scope;
    in fact it is illegal to delete one explicitly.



    An equivalent way to achieve this is with the command SET name LOCAL,
    after which the vector may be SET in local scope (so
    SET x LOCAL SET x=10 SET x=20 is equivalent to
    LOCAL SET x=10 SET x=20).



    Note that, as usual, you may have to be a
    little careful to ensure that you don't exit a macro before you expect.
    The symptoms would be that your local vector was already destroyed, or that
    it referred to one at less restrictive scope (see section The Command Interpreter).
    The easiest fix is to add a comment line to the end of the macro.



    With expressions separated by commas the SET command is like a DO loop,
    setting
    name to be the values between expr1 and expr2, at
    increments of expr3 (which defaults to 1). You can also use an
    implicit DO as part of an expression, e.g. SET x=1 + do(0,10,2)/10
    (see section Arithmetic).



    The command with ? and : is similar to the C ternary operator.
    If expr1 is true,
    take the corresponding value of name for expr2, otherwise
    use expr3. This command is worth learning, as it can often be

    used to replace a DO loop. This command is in fact simply a special case
    of SET x = expr.



    If you have a DO loop that calculates each element of a vector in turn,
    something that is possible if inefficient in SM,
    (23)
    you need to define a vector before you use it. You will also need to
    declare a vector (or create it by putting it on the left of a SET command)
    if you want to use a vector-valued subscript on the left of an expression.
    This can be done with
    the SET DIMEN(name) = INTEGER, which also initialises it to 0.
    Thus SET DIMEN(y) = DIMEN(x) is
    equivalent to SET y = 0*x. You cannot use expressions as the
    dimension, but SET y = $(4 + 4) works perfectly well.
    You can optionally specify a qualifier to the dimension, in just the same way
    that you can specify a qualifier to a column in a READ command, so
    SET DIMEN(s) = 10.s declares a 10-element string-valued vector.


    See also SET WORD [ expr , expr ] = val.



    SET name = WORD ( [ arg [ , arg ... ] ] )
    allows you to use a macro
    as a sort of function definition. Within the macro WORD any
    assignment to $0 has the effect of assigning to name, and the
    other arguments behave as normal. The arguments arg can be words
    or numbers (but not general expressions) and are separated by commas.

    Note that this is a change to
    the syntax of this command!
    Previously only one argument was
    permitted, but it could be an expression, and the result was returned
    by assigning to $1 in a rather confusing way.



    SET word[expr] = expr sets the elements expr
    of vector word to the values of the vector on the right hand side.
    If the left hand side is a string but the right hand side is numerical
    it will be converted.
    The first expr

    is converted to an integer before being used as an index; if it is too small
    it's set to 0, if too large to the largest allowable index.
    For example,

    	set i=0,10 set x=100*i
    	set dimen(y) = dimen(x)
    	set y[i-1] = x
    


    will result in a complaint that -1 is an invalid index
    and set y = { 100 200 300 ... }.
    Note that
    arrays are subscripted with [ ] not (), and that, as always, indices start
    at 0 not at 1. The word must exist before you can do this to it.


    If your range of indices is contiguous you can say:

            set x[0,10] = y
    


    instead of

            set i = 0, 10
            set x[i] = y
    


    As a bonus the vector x will be extended
    as needed to accomodate the new elements. This means that

            set x = x CONCAT y
    
    


    is equivalent to

            set x[dimen(x), dimen(x) + dimen(y) - 1] = y
    


    If you have pre-allocated x to be large enough,
    the latter is (maybe much) more efficient.



    This also provides a way to generate a vector initialised to a desired
    value:

            set x[0, 100] = 10
    
    


    SET IMAGE[ix,iy] is used to set elements of an image to the specified values.
    The image must exist (see section Image), and the vectors ix and iy are interpreted
    as integer subscripts into the image (0-indexed, of course). This is the
    inverse of the SET z=image[ix, iy] and isn't quite
    the same as the SET z=IMAGE(x,y) command, as x and y are interpreted with
    using the (optional) xmin, xmax, ymin, and ymax values. In the old days, this
    command was set image(ix,ix) = ..., but this was confusing and is
    now deprecated.



    SET HELP sets the help string for a vector; the rest of the line is read,
    and will be returned in response to a HELP WORD request. It can
    also be used in the string-valued expression HELP(name), for example
    YLABEL $(HELP(yvec)).



    SET RANDOM number sets the seed of the random number generator used by the
    RANDOM operator; if you don't set it yourself it'll be set to some value
    based on the time since 1970.



    Let's look at some examples.

    SET y = $v1 + 5.0 * x
    


    This sets each element of the vector y to be the value of the
    scalar $v1 plus 5.0 times the corresponding element of the
    vector x

    (assuming that x has been defined previously)

    SET data_set_1 = lg(x) IF ( lg(x) > 0)
    


    This sets the elements of the vector data_set_1 to be the (common)
    logarithm
    of the corresponding element of the vector x, if that logarithm is

    > 0. Thus data_set_1 will in general be of smaller size than x.

    SET data = (lg(x) > 0) ? lg(x) : 0
    


    In this case, data_set_1 will be the same size as x, and any
    elements of data_set_1 where the corresponding element of

    x is less than or equal to 1, will be set to 0.

    SET vec = 4*{ 1 1.5 2 2.5 3 }
    


    will define a vector vec, with 5 elements, with the values given
    by four times those in the list.

    SET vec = 1,12,2 
    


    an alternative way of defining the same values.

    SET i = { 2 3 }
    SET x = vec[i]
    


    will set the vector x to have be 8 10 (i.e. vec[2]
    and vec[3]).

    MACRO pow 2 { SET $0 = $1 ** $2 } 
    SET vec = pow(vec , 3) 
    


    cube the vector vec.

    SET vec[0] = 2*pi
    


    Change your mind about the first element of vec.

    
    SET HELP pam Wichita, Kansas, July 7, 1953
    


    will set the help string for vector pam to be the string
    Wichita, Kansas, July 7, 1953, so when you type
    HELP pam, this string will be printed out.

    SET rhl=Robert
    

    defines a string vector with one element.

    SET DIMEN(rhl) = 10.s
    


    defines a string vector with ten elements (all blank), while

    SET rhl={Robert Horace Lupton}
    


    defines a string vector with initialised elements, and

    SET rhl[1]=Hugh
    


    corrects it.



    See the CURSOR command for defining a pair of vectors using the
    cursor to mark the points, and SPLINE for how to fit splines
    to pairs of vectors.



    Shade

    Syntax: SHADE number pexpr pexpr
            SHADE HISTOGRAM number pexpr pexpr
            SHADE HISTOGRAM ANGLE number pexpr pexpr
    




    (`Pexpr' is the name of a vector, or an expression in parentheses,
    e.g. SHADE 1000 x (sqrt(y))).



    Shade `inside' a curve defined by the expressions. The shading is
    rotated through the current value of ANGLE, and lines are
    spaced by the integral part of dnumber apart (screen
    coordinates, so the full screen is 32768 across). If number is
    0, the lines will be drawn as close together as the device allows,
    simulating an area fill. This is a very inefficient way to fill areas,
    made only slightly better by specifying a large LWEIGHT on
    devices that support such things in hardware (you'll also get slightly
    jagged edges).



    If number has a fractional part, the lines are offset by that
    fraction of the spacing (try shade 100 x y ctype red shade 100.5 x y).



    The meaning of `inside' is that as the shading is done, from
    left to right taking the value of ANGLE into account, lines are drawn
    from every odd to every even crossing of the curve. The curve is
    considered as being closed by joining the first to the last point. If
    a shading line just touches the curve the algorithm may be confused,
    change number slightly, or try adding 180 to ANGLE. Sometimes
    joining the ends of the curve may
    not be what you want, try using CONCAT to add points on the end
    yourself. For example,

    SET x=0,10 SET y=x**2 LIMITS x y SHADE 1000 x y
    


    looks like a new moon, but

    SHADE 1000 (x CONCAT 10) (y concat -1e10)
    


    shades beneath the curve, for ANGLE 0 that is.
    You could also try the macros scribble and shading in
    demos, e.g. type load demos scribble.



    SHADE HISTOGRAM is similar, but it shades the histogram that would
    be drawn by HISTOGRAM from the same set of points. In this case the
    area to be shaded lies between the histogram and the line y=0. If this
    offends you, offset the whole graph and lie about the axes.



    The form with ANGLE is used for shading a histogram of y against x,
    when the averaging is done in the y- not the x- direction. Compare

    set y = {0 3 1 3 1 0} set x =-0.25,-2.75,-0.5 lim y x
    ERASE box shade histogram 0 y x
    


    with

    ERASE box shade histogram angle 0 y x
    


    Show

    Syntax: SHOW 
    



    List the values of some of the internal variables, including
    current location
    and plot region limits in user and device coordinates, the value of
    the expansion and angle variables, the line type and weight, and the
    physical limits. Show is actually a macro, so you could modify
    it to your own ends, for example listing the current data file too.



    Sort

    Syntax: SORT { vector_list }
            SORT < vector_list >
            SET vec = SORT ( expr )
    




    Sort the first vector in the list into increasing numerical order, and
    rearrange the others in the same way. The maximum number of vectors that can
    be sorted is 10. For example, following the commands

    SET e = { 2 7 1 8 2 8 1 8 2 } SET p = { 3 1 4 1 5 9 2 6 5 }
    SORT { e p } 
    


    the vectors e and p would be 1 1 2 2 2 7 8 8 8 and

    4 2 3 5 5 1 1 9 6 . The order within the p vector is
    not defined when the e values are identical.



    Any mixture of string- integral- and arithmetic-valued vectors is allowed.



    You can also use SORT to sort a single expression, returning an expression;
    e.g.

    SET x=0,10 SET y = SORT(FLOAT(x)) + SORT(SIN(pi*DO(0,1,0.1)))
    


    (actually, you don't need the FLOAT, but you'll get a warning
    if VERBOSE is 2 or more).



    Spline

    Syntax: SPLINE x1 y1 x2 y2
    




    Fit a natural cubic spline through the points specified by vectors x1 and
    y1.
    The dimensions of x1 and y1 must be the same and must exceed 2,
    x1 must
    be monotonic increasing (use SORT if necessary). When the spline
    has been fit, take the points
    specified in vector x2, and fill the (new) vector y2 with the
    corresponding values. Linear interpolation is used beyond the ends of

    x1.



    Strings

    Strings
    










    SM supports a number of string operations on vectors and scalars. In the
    following descriptions expr is a expression and vector the name of a vector.


    Unary:
    



    ATOF(expr)


    The value of expr converted to a floating point number. If an element of the
    expression cannot be so interpreted (i.e. it doesn't start with an optional
    sign followed by a digit), the value returned will be 0.

    CTYPE(STRING)

    Return a vector with the names of all currently defined colours; there
    is also CTYPE() to recover their values (see section Arithmetic).

    HELP(name)

    The help string associated with vector name (set with SET HELP)

    LENGTH(expr)


    The length (SCREEN units) that a string would have if plotted

    STRLEN(expr)

    The number of characters in a string

    STRING(expr)

    Convert a number to a string. You might prefer to use sprintf('%t',expr)
    instead, as it gives you more control.

    STRING<WORD>

    Convert a string to a string, quoting ". You don't usually need to
    use this (simple write 'my string'), but if your string already
    contains quotes this doesn't work.

    ( expr )

    Raise precedence

    Binary:
    

    expr + expr

    Add; concatenate element by element

    expr CONCAT expr

    Concatenate the two vectors

    INDEX(expr_1,expr_2)

    Return the starting index of expr_2 in expr_1, or -1 if not found.

    SPRINTF(expr_1,expr_2)

    Format expr_2 using the standard C format string expr_1. The additional
    format %t or %T is identical to %e, but formats the string as a power of
    10 in TeX format. Note that only one expr may be formatted, but that
    you can say sprintf(expr,expr) + sprint(expr,expr) ... to
    work around this restriction.

    vector[expr]


    The elements of vector given by expr.

    Ternary:
    

    SUBSTR(expr_1,expr_2,expr_3)

    Return the substring of expr_1 that starts at expr_2 and is expr_3
    characters long. If expr_2 is negative, count from the end of the string;
    if expr_3 is 0 return the rest of the string. For example,
    'Dr. ' + substr('Ralph Monger',-6,0) would return 'Dr. Monger'.

    expr1 ? expr2 : expr3

    expr2 if expr1 is true, else expr3



    Node that this is similar to the corresponding SET command, but
    it needs parentheses if used as an expression.



    All indices, as elsewhere in SM, start at 0; e.g.
    substr('Algonquin',0,1) is A.


    The expression VECTOR[expr] results in a vector of the same
    dimension as the expr, with elements taken from VECTOR
    (i.e. VECTOR[INT(expr_i)]).

    You can also use WORD([ expr [ , ... ]]) as part of
    an expression, where WORD is a macro taking zero or more arguments.
    The arguments are restricted to be either the names of vectors or numbers;
    sorry.



    You can use the usual logical operators (see section Logical) with string-valued
    vectors ; there's a
    discussion in that section of the confusions that people conjure up about
    when they need to use ".



    The HELP(name) string operator is often useful in labels, for example

            SET HELP size "r_e"
            ...
            XLABEL $(HELP(size))
    



    The precedences are what you'd expect, with + being higher than
    CONCAT. The logical operators have even lower precedence than
    CONCAT.



    Surface


    
    Syntax: SURFACE type z1 z2
    or      SURFACE type z1 z2 WORD WORD
    


    Draw a wire-frame surface of the current IMAGE from the point
    defined by VIEWPOINT. If the WORDs
    are omitted a line in the surface will be drawn for each row and column
    of the image; if the WORDs are present they will be taken to be the
    x- and y- coordinates of the desired lines, and SM will
    interpolate in the image to determine
    the corresponding values (see also the hundreds digit of type, below).


    The command VIEWPOINT specifies the position of the observer
    and the type of projection used (see section Viewpoint).



    The last digit of TYPE is used to determine which surface to draw:

            0       no hidden line removal
            1       draw top surface
            2       draw bottom surface
            3       draw both top and bottom surfaces
    


    If type's tens digit is set, SURFACE will use the current
    limits (as set with LIMITS) rather than autoscaling them from the
    data.



    If type's hundreds digit is set, the two WORDs are taken to
    be the x- and y- coordinates corresponding to the rows and
    columns of the IMAGE, but no interpolation is done. For example, after

    IMAGE (11,11)
    SET ix=0,10
    set xs=0,10,2
    do y=0,10 {
       SET IMAGE(ix,$y) = cos(0.2*ix)*sin(0.4*$y)
    }
    VIEWPOINT 30 -10 -1
    SURFACE 3 -1.1 1.1 xs xs
    


    will draw a 2-sided surface, drawing 21 lines in each direction on
    the surface. If, on the other hand, the data were really only known on
    at irregular set of x- and y-values, you could say something
    like

    IMAGE (11,11)
    SET ix=0,10
    SET x = { 0 1.3 2.4 3 4 4.5 4.6 6.7 8.2 9.6 10 }
    SET y = { 0 0.4 0.9 1.2 2.718 3.14 4.2 5.4 6.667 9.1 10 }
    do i=0,10 {
       SET IMAGE(ix,$i) = cos(0.2*x)*sin(0.4*y[$i])
    }
    CTYPE cyan
    SURFACE 103 -1.1 1.1 x y
    CTYPE default
    


    to draw the same surface.



    If TYPE's thousands digit is set, the surface is not clipped to
    the z-axis limits z1 and z2.



    z1 and z2 are the limits used for the z-axis;
    you might want to set them with MINMAX. The surface drawn will
    be truncated at z1 and z2 unless you are using an
    axonometric projection (see section Viewpoint).



    There are some useful macros in the file `surfaces'; say
    load surfaces to read them. If VERBOSE is one or more, a helpful
    header will be printed when you load the file.



    Table

    Syntax: TABLE [subtable] ['format'] file
            TABLE subtable \n
            READ TABLE { WORD [WORD ...] }
            READ TABLE 'format' { WORD [WORD ...] }
            READ TABLE 'byname' { WORD [WORD ...] }
            READ TABLE 'bycolumn' { WORD id [WORD id ...] }
            LIST TABLE
    




    SM is able to read a wide range of table formats, using tricks similar
    to those used for the IMAGE command. The variable table_type is used to
    specify which you want (and may be set in your `.sm' file). Common values
    are bintable and ctable. Values flagged as bad in the table
    may be (in the case of bintable, are) set to SM's invalid value,
    and this are not even equal to themselves.



    TABLE [...] file is the equivalent of the DATA command, and sets
    file file to be the source of data read with the READ TABLE command;
    if the file can't be opened for read, you will be warned. If the
    subtable argument is provided, it specifies which table in a TABLE
    file is to be read; this is only currently supported for FITS tables
    ($table_type is bintable or a type derived therefrom; for such
    tables
    you probably want to use a subtable of 1). The format, if provided,
    specifies the types of the columns in the table; some tables may
    provide this either in the table header (e.g. FITS binary tables) or
    in the filecap file, as the FM quantity. Allowable format strings are
    specified at the end of this file. This format applies to READ TABLE
    commands for this table, unless specifically overridden.



    The range of lines specified by LINES is reset; the LINES command may
    be used to select portions of TABLEs to read.



    If you don't specify the filename, and if SM knows how to skip tables,
    it will skip over HDUs that it has already read, provided that the SM variable
    save_read_ptr is set (which it is by default; see section Read).


    The READ TABLE command is used to read data from a table. If you
    specify a format string and a list of names, a vector will be read from
    each column specified in the format and assigned to the corresponding
    vector (for example, READ TABLE 'x16if2' { i x y } will skip 16
    bytes at the start of the row, then read an integer into i, and
    two columns of floats into x and y). Format strings are
    described at the end of this section.



    If you specify the format as 'byname', the names of the
    vectors will be taken to be the names of columns in the file, and the
    corresponding columns will be read. If the column name, say RDL,
    specifies an array, the vector will be filled from column RDL[0];
    as an alternative to this you can specify the name as (e.g.)

    RDL[2] in which case vector RDL2 will be created from
    column RDL[2].
    You can also say RDL[0-2] to read vectors RDL0, RDL1,
    and RDL2.

    Byname access is only currently supported for
    FITS binary tables (as a special case, you can specify byname as
    the format in a filecap file).



    The name that you give will be used as the name of the vector, but the
    matching with the binary table is done without regard to case, so

            read table 'byname' { AlGoNqUiN }
    


    and

            read table 'byname' { Algonquin }
    
    


    will read the same column of the table into two different vectors,
    AlGoNqUiN and Algonquin.



    For tables where byname formats are acceptable,
    you can list the available column names with LIST TABLE.


    If you specify the format as 'bycolumn', the list is expected to be a
    list of pairs of values (similar to the regular READ { x 1 y 2 ... }
    command).
    The first element of each pair is the name of a vector, the second may be
    either a number or a column name (if supported). The number gives the
    desired column with respect to the current format string. For example,

    	TABLE 'd*' file
    	READ TABLE 'bycolumn' { x 1 y 2 }
    


    will read x and y from the first two columns of the file, whereas

    	TABLE 'x8d*' file
    	READ TABLE 'bycolumn' { x 1 y 2 }
    


    will read x and y from the second and third columns of the file,
    assuming that a double (the d) is eight bytes wide.


    Instead of a number, you may be able to specify a column name, for
    example

    	READ TABLE 'bycolumn' { x_u rowc[0] x_g rowc[2] }
    


    but this depends on your chosen $table_type having support for
    byname access. In general you will not be able to mix name- and column-
    orientated access (for example, we do not support column orientated
    access to FITS binary tables unless you provide a format).



    TABLE's formats are strings (i.e. they must be enclosed with ").
    consisting of a set of types followed by optional repeat counts, for
    example 'x12f5d*' would specify a table, each of whose rows had 12
    unwanted bytes, 5 floats, and the rest integers. Format letters are:

    a

    A 1-byte ascii string
    c

    A 1-byte char
    d

    An 8-byte double
    f

    A 4-byte float

    i

    A 4-byte int
    l

    A long int (may be 8 bytes on some machines)
    s

    A 2-byte int
    x

    1 byte to skip (a space may be used instead of an x)



    and each may be followed by a repeat count (default: 1), or a *, meaning
    to repeat as many times as fits into a row. In all cases except
    a, the repeat count refers to how many columns there are (so
    d4 means 4 doubles); for a it refers to the length of the string
    (so a4 is one 4-byte string). Note that the maximum length of an a
    table is the length of an element of a string-valued vector (usually
    40, but configurable by whoever built your copy of SM).



    Header keywords may be available with the DEFINE name IMAGE command.



    Termtype

    Syntax: TERMTYPE word [ INTEGER ]
    







    Set the terminal type to be WORD. This has nothing to do with
    graphics, but is to do with the history and macro editors. WORD

    is case-sensitive. With two exceptions, the properties of the terminal
    will be read from the termcap file (see section Termcap -- A Terminal Database). If WORD
    is dumb SM tries to support editing on a (very) stupid terminal.
    If this isn't what you want, for example you are running SM from within
    emacs TERMTYPE none is equivalent to starting SM with the -s
    flag and entirely disables input line editing (although commands
    are still remembered so commands like playback and hcopy

    will still work). You can turn editing back on by issuing a TERMTYPE
    command with a valid terminal name.



    For most purposes you don't even need to use
    this command, as when SM starts up it reads the value of the
    environment variable TERM (under Unix) or logical variable (under VMS)
    it effectively issues a TERMTYPE command with its value as
    argument. If you have a term entry in your `.sm' file
    this takes precedence over any TERM variable. For example, a

    term entry of selanar -21 is equivalent to the command
    TERMTYPE selanar -21.



    You also should not have to use the optional INTEGER argument,
    which specifies the number of lines that will appear at a time when
    LISTing things, as this information
    is usually derived from termcap. If you are using a window system,
    then termcap may be wrong and this argument may be useful.
    Another exception occurs when you wish to
    disable cursor motion to avoid having your graphs scrolling off the
    screen. If this concerns you see section Termcap -- A Terminal Database.




    Ticksize

    Syntax: TICKSIZE SMALLX BIGX SMALLY BIGY
    






    Determine tick intervals for BOX. SMALLX refers to the interval
    between small tick marks on the x axis, BIGX refers to the
    interval between large ticks and so forth. If BIG is 0, the axis
    routine will supply its own intervals according to the label limits.
    If SMALL < 0, the axis will have logarithmic tick spacing and
    BOX assumes that the limits are logarithms, e.g. -2 and 2
    refers to limits of 0.01 and 100.
    If both BIG and SMALL are 0, you'll get SM's default
    behaviour.



    Negative values of SMALL and BIG are interpreted as
    specifying the tickspacing in the decade 1:10, and are scaled to fit
    the decades actually plotted. For instance, if you say

    LIMITS 0 1 3 4
    TICKSIZE -1 10 -0.1 1 BOX
    


    then the x-axis will have small ticks at 2, 3, ..., 9 and big ticks at
    1 and 10, while the y axis will have small ticks at 1100, 1200, 1300, ...
    and big ticks at 1000, 2000, 3000, ... (You might want to use NOTATION
    to stop SM using exponential notation for the 10000 label). The most
    usual TICKSIZE is probably -1 10, and this may be written -1 0

    for backwards compatibility.



    Occasionally you may want to use the same tickspacing in all decades
    of your plot. To do this make BIG negative also in which case the
    spacing used for the first decade plotted will be used for all decades.
    (Note that this means that if the axis is plotted backwards then the
    value from the largest decade will be used):

    LIMITS 1.9 2.1 2.1 1.9
    TICKSIZE -0.1 -1 -0.1 -1 BOX
    


    this is a good way to make an axis very crowded!



    If you really cannot use TICKSIZE to accomplish your needs, you can use
    AXIS and provide vectors specifying the positions of the big and little
    ticks, and even the axis labels.


    User

    Syntax: USER ABORT [ string ]
            USER integer string
    




    The first form, USER ABORT, is used to generate a syntax error, and
    return to the prompt (with a traceback if you've requested one with the
    traceback variable). The
    command reported as the offender is string if provided, otherwise

    USER ABORT.



    If you want to catch these errors you can define a macro
    abort_handler which will be called with the message as all of its
    arguments instead of causing SM to return to the command prompt. For
    example, I use

    abort_handler 111	# catch USER ABORT
    		        echo Caught user abort: $1
            		#
    


    Note that the argument extends to the end of the line -- this is important!
    If abort_handler took a single argument, what would the command

    USER ABORT good bye world do? First the handler would be called
    as abort_handler good bye world. It'd pull off the first argument
    good and print it and SM would continue to process bye as
    a command. It's neither a command nor a macro, so the default
    macro_error_handler executes
    USER ABORT bye is not a macro; aborting. Rest of line: world. The
    abort handler pulls of the bye, and tries to execute is ---
    and we have an infinite recursion that is broken only by a ^C or by
    reaching the maximum depth to which SM will nest abort handlers.








    The other, with an integer, calls a function called `userfn',
    passing the integer and the
    string as arguments, both are passed by address as if SM were
    written in fortran (string is passed as a NUL terminated C string, though).



    This function is provided to allow users without C compilers to make
    additions to the main grammar, but whether it is really useful is a
    different matter. Currently, if integer is non-zero then both

    integer and string are printed unless integer is
    1, in which case the command
    USER 1 r 1.23 is equivalent to SET r=1.23 (only constants
    are allowed).



    If string is dump you'll get a macro stack trace, and if
    it's segv you'll get a segmentation violation (on purpose). If
    you really want some new functionality, send us mail.


    Verbose

    
    Syntax: VERBOSE INTEGER
    





    Make SM produce output on what it is doing if INTEGER is > 0.
    Setting VERBOSE to 0 is a way of only listing `important' (non-system) macros,
    and generally getting a little peace and quiet. It has the considerable
    disadvantage that you can think that you are reading data from files, while
    actually something is wrong. For this reason the default value is 1. A value
    of 2 or more is basically useful for debugging. If you get some nondescript
    syntax error and don't know where it is coming from, VERBOSE of 3 or 4 will
    trace your programme, and should help find the problem. The original error
    message will tell you which macro SM thinks it is processing
    when the error occurred but it will be wrong if the macro
    had been fully scanned when the error is detected. In this case it will
    report a parent of the current macro. The reason for this behaviour is
    related to why RETURN can return from the wrong place
    (see section The Command Interpreter).



    If you want to know the current value of VERBOSE you can use the
    SHOW command (actually a macro), or try

    DEFINE verbose DELETE echo Verbose: $verbose
    


    which is (of course) what SHOW does anyway.



    If verbose is one or more SM will:

    • Complain about things like division by zero, and logs of negative
      numbers the first time that they occur in a given expression

    • Correct you when you use the wrong format to print a vector

    • Identify the X11 device that you switch to with -dev [+-]

    • Include all macros in macro listings, even those starting ##

    • Indicate line where arithmetical errors occur

    • List all non-printing key-bindings with LIST EDIT

    • Note more than 40 curve crossings in SHADE

    • Notify user when a control-C stopped the production of a hardcopy

    • Output a little extra about RESTORE and SAVE

    • Print lines beginning # while reading macro files

    • Provide some context with APROPOS on help files

    • Realise that a WINDOW number is out of range

    • Report which lines are read from a file using READ

    • Remind you that mixing LOCATION with WINDOW confuses people

    • Say something about format and size of IMAGE files

    • Suggest that you change LOCATION to make room for axis labels

    • Tell you what keys to use with the cursor

    • Warn about zero-length vectors

    • Whinge about missing fields with DEFINE var READ # #

    • Write a note when it finds out-of-range values while contouring IMAGE files


        if INTEGER is two or greater, then also :

      Announce when the do, foreach, input, or macro stacks are extended

    • Complain if an environment or SM variable is not defined

    • Echo lines in data files that start with #

    • Include `internal' variables in LIST DEFINE output

    • Inform you when it seeks to a line in a data file

    • List all key-bindings with LIST EDIT

    • Note attempts to `unput' off bottoms of buffers (this is related to the
      implementation of macros and variables)

    • Point out attempts to delete local variables and vectors

    • Print the fraction of axes covered by the tick labels

    • Prompt for variables, even if they are on the macro buffer

    • Protest if you reference an undefined history number

    • Remark if a variable is referenced in a graphcap SY string, but not provided

    • Remind you that only a finite number of KEY commands can be processed

    • Repeat complaint about things like division by zero, and logs of
      negative numbers every time that they occur

    • Report vectors of different lengths in PRINT

    • Say when a vector is used as a scalar.

    • Tell you when vectors are redefined.

    • Write a note when it finds out-of-range values while contouring IMAGE files.


      if INTEGER is three or greater, then also :


      List each macro name just prior to expansion.


      if INTEGER is four or greater, then also :


      Print each token as it is recognised along with its text. The number in

    • column 1 is the value of `noexpand', the level of nesting of {} loops.

    • Show expansions of variables.


      if INTEGER is five or greater, then also :


      Print the contents of DO, FOREACH, IF, and MACRO command lists.

    • Prompt for DEFINEing variables and the values of multi-word variables.


      If you set a negative verbosity, then if the parser was compiled
      with DEBUG defined, you'll get a veritable torrent of debugging
      information. Use another negative VERBOSE command to turn it off again.



      Version

      Syntax: VERSION 
      



      Return a string identifying the version of SM in use. If you have
      any reason to communicate with SM's authors, we'll want to
      know which version you are running. As a matter of fact, version is
      a macro to print $version.



      Viewpoint


      Syntax: VIEWPOINT theta phi l
      


      Surfaces are drawn from a direction (THETA,PHI), and projected onto
      a surface passing through the origin. The projection is from a point

      L away from the nearest corner of the cube containing the image. If
      L is positive a perspective projection is used; if it is 0 the viewpoint
      is taken to be infinitely far from the surface, and if it is negative
      an axonometric projection is used (i.e. the surface is projected from
      infinity onto the x-z plane).



      The coordinate system is such that the z-axis is THETA=90, the
      x-axis is (THETA,PHI) = (0,0), and the coordinate system is right
      handed. Angles are taken to be in degrees, with theta lying in
      [-90,90] and phi lies in [-180,180]. The nearest corner of the cube
      containing the surface is projected onto the point (0,0).



      There are some useful macros in the file `surfaces'; say

      load surfaces to read them. If VERBOSE is one or more, a helpful
      header will be printed when you load the file.



      Whatis

      Syntax: Whatis ( expr )
      





      WHATIS(something) has a value depending on what something is:

      a number:       0
      not a number:           set 01 bit    (bit 0)
        a macro:              set 02 bit    (bit 1)
        a variable:           set 04 bit    (bit 2)
        a vector:             set 010 bit   (bit 3)
           a float vector:    set 040 bit   (bit 5)
           a string vector:   set 0100 bit  (bit 6)
           a long vector:     set 0200 bit  (bit 7)
        a keyword:            set 020 bit   (bit 4)
      


      So if "aa" is the name of a string vector, WHATIS(aa) has the octal
      value 0111, or 73,
      whereas WHATIS(HELP) has the value 021, or 17, and WHATIS(1) is 0.
      There is a macro in `utils' called is_set that tests if WHATIS
      sets a particular bit, for example

      	if(is_set(kkk,3)) { echo kkk is a vector }
      


      tests if bit 3 (vector) is set for "kkk" and prints its findings;
      it's easier to say

      	if(is_vector(kkk)) { echo kkk is a vector }
      


      which does the test for you.


      Window

      Syntax: WINDOW nx ny x y
      





      WINDOW makes the current plot location the window at (x,y), where there
      are nx windows across and ny windows up and down.
      WINDOW 1 1 1 1 resets the plot location to the entire plot area.
      The size and placement of the windows is decided by the value of
      EXPAND when the WINDOW commands are issued, so be sure that EXPAND has the
      same value for every window in a set. (It's used to figure out the
      axis labels, and spacings between boxes).
      While plotting to a given window you can of course change EXPAND
      to your heart's content.



      If the number of windows in either the x or y direction is
      negative no space is left between the boxes in that direction
      (try DO i=1,3 { WINDOW 1 -3 1 $i BOX }). It's possible to
      overload `window' and `box' to only label external axes in blocks of
      touching boxes.



      If either x or y is specified as, e.g. 2:4, the window is set to
      cover the range 2-4 (i.e. the part of the screen covered by windows 2,
      3, and 4). Note that this feature can be used to split the screen in
      arbitrary ways, e.g.

          window -1 -6 1 1:5 box
          window -1 -6 1 6 box
      


      (or you could say window -20 -20 15:19 15:19 as an alternative to a
      LOCATION command).



      If you don't want boxes that touch, but you don't like the gaps left
      between boxes by the WINDOW command, you can now do something
      about it legally, without lying to SM. After we calculate the widths
      of the `gutters' between the windows that we think that you need, they
      are multiplied by the values of the SM variables x_gutter and

      y_gutter, so if you think that the spacing is too large in the
      x direction you can say

      define x_gutter 0.5
      window 2 2 1 1 box
      window 2 2 1 2 box
      


      to make things look better. Within a macro it can be convenient to
      say local define x_gutter 0.5, as then the gutter value softly
      and suddenly vanishes at the end of the macro.



      It's confusing to change LOCATIONs while using WINDOWs; you probably want
      to say WINDOW 1 1 1 1 first.


      While

      Syntax: WHILE { expr } { commands }
      



      Repeat the commands while the expr is true.
      You can break out of the loop early with the BREAK command (see section Break).



      There is further discussion in section See section DO and FOREACH loops, WHILE loops, and IF statements.



      For example,

      define i 0
      while{$i < 10} {
              echo Hi $i
              define i ($i+1)
      }
      


      is equivalent to either

      do i=0,9 {
              echo Hi $i
      }
      


      and

      set i=0
      while{i != 100} {
              if(i == 10) { break }
              echo Hi $(i)
              set i=i+1
      }
      


      except in so much as which variables and vectors are defined at the end.



      Write

      Syntax: WRITE STANDARD string
              WRITE [+] WORD string
              WRITE HISTORY WORD
      
      





      WRITE STANDARD writes a string, followed by a newline,
      to the standard output. The string is taken to be the rest
      of the line up to a carriage return (which may be written explicitly as \n).
      The macro echo is usually used as an abbreviation for this command.
      WRITE WORD is similar, except that the string is written to file
      WORD.
      If the filename is the same as the previous WRITE, or if you preface the
      filename with a +, the string is
      appended, otherwise the file is overwritten.





      WRITE HISTORY WORD, writes macro WORD onto
      the end of the history list.



      For MACRO WRITE, see under macros.



      Xlabel

      Syntax: XLABEL str
      




      Write the label str centered under the x axis made by BOX.
      The string is taken to be the rest
      of the line up to a carriage return (which may be written explicitly as \n).
      If you think that the label is badly positioned you can say things like

      XLABEL \raise-500My X-axis Label
      


      (providing that you use TeX-style fonts, of course)



      If the label is too tall it may overlap with the numerical tickmark
      labels. If VERBOSE is one or more, you'll be warned about this, and
      a suggested change to the plot LOCATION will be suggested. This moves
      the entire plot; it is your responsibility to reset it later if appropriate.



      If ANGLE is non-zero, it will be used to determine the direction of
      the label, otherwise it is parallel to the x axis.



      See section Drawing Labels and SM's TeX Emulation, for a description of how
      to enter a label with funny characters, sub- and super-scripts, and so forth.



      If EXPAND is set to exactly 1, and ANGLE is exactly 0, then SM
      will use hardware fonts, when available, in writing labels. This is faster,
      but if you don't like it say "EXPAND 1.00001", or start the string with a
      \0 which does nothing, but forces the software character set.


      Ylabel

      Syntax: YLABEL str
      




      Write the label str centered to the left of the yaxis made by BOX.
      The string is taken to be the rest
      of the line up to a carriage return (which may be written explicitly as \n).
      If you think that the label is badly positioned you can say things like

      YLABEL \raise500My Y-axis Label
      
      


      (providing that you use TeX-style fonts, of course)



      If the label is too tall it may overlap with the numerical tickmark
      labels. If VERBOSE is one or more, you'll be warned about this, and
      a suggested change to the plot LOCATION will be suggested. This moves
      the entire plot; it is your responsibility to reset it later if appropriate.



      If ANGLE is non-zero, it will be used to determine the direction of
      the label, otherwise it is parallel to the y axis (ANGLE 360 will
      achieve horizontal labels).



      See section Drawing Labels and SM's TeX Emulation, for a description of how
      to enter a label with funny characters, sub- and super-scripts, and so forth.


      If EXPAND is set to exactly 1, and ANGLE is exactly 0, then SM
      will use hardware fonts, when available, in writing labels. This is faster,
      but if you don't like it say "EXPAND 1.00001", or start the string with a
      \0 which does nothing, but forces the software character set.

      Appendices

    • 2-D Graphics: Two-Dimensional Graphics
    • Tables: Reading and writing tables
    • Termcap: Termcap -- A Terminal Database
    • New Devices: Adding New Devices, and Porting to New Machines
    • Libraries: The System Macro Libraries
    • Mongo: Tips for Mongo Users
    • Fonts: SM's Fonts
    • The Command Interpreter


      The basis around which the command interpreter is written is a grammar
      which is passed a set of tokens ( analogous to words in English )
      which it parses, given a set of grammatical rules. As it recognises
      each rule, it executes the code associated with that rule.
      See section The SM Grammar.



      An example would be:

              aa : BB CC
                 {
                    printf("Rule BB CC found\n");
                 }
      

      which specifies that the rule aa consists of the token BB followed by
      CC,
      and that if rule aa is recognised the programme should print that fact
      out. Conventionally, uppercase names are reserved for `terminal symbols',
      and lowercase for `non-terminal symbols' where terminal symbols are
      those that are passed to the parser ( analogous to words ), and
      non-terminal symbols are tokens that the parser has constructed out of
      terminal symbols (analogous to phrases). The right hand side of a rule
      may contain a mixture and non-terminal symbols, and symbols may be
      assigned a
      value(24).

      Token Generation




      SM generates tokens for the grammar roughly as follows:
      When characters are typed at the keyboard, they are read by a routine
      which runs in CBREAK mode (PASSALL for VMS), and
      receives each character as it is typed. It is this routine that handles
      command line editing, the history system, and
      key bindings.(25)
      Following a carriage return, it passes the whole line to the
      lexical analyser, which divides
      the input stream into integers, floats, strings, or words. In addition it
      recognises ${}^ as having special meanings (see below under
      variables ($) and history (^)). As in
      C, the escape sequence `\n' is replaced by a newline, which means that
      commands which read to the end of the line may be fooled into thinking
      that they have found it; see the examples at the end of the section.
      A { sets the flag `noexpand', which
      turns off the interpretation of all special symbols, and causes all
      tokens to be returned as WORD. The matching } unsets this flag.
      This mechanism is used in defining macros and various lists.
      A word is anything which is not otherwise recognised, so for
      example `hello_there.c' or `1.2e' would be considered words.
      Symbols are separated by white space, taken to be spaces tabs or newlines,
      or the characters !, {, }, +, -,

      *, /, =, ?, !, ,, <,
      >,
      (, or ). This behaviour can be modified by enclosing a string in
      double quotes, when no characters (except ^) are special, and
      tokens are delimited only by the end of the line, or some character
      after the closing quote.
      Enclosing in quotes is rather
      similar to enclosing in {}, except that quotes have no grammatical
      significance. A string in double quotes is always treated as a word,
      but the quotes must not have been discarded by the time that the
      lexical analysis occurs.



      For example, "2.80" is a float, as SM will have digested
      the " before looking at the string. You can fool it with "2.80 ".
      A string begins with a ' and continues to the next ': they
      are used in certain contexts where SM needs to know if a
      WORD or STRING is involved, for example in a PRINT

      command. It's worth noting that the '...' are stripped when the
      string is recognised -- if you need to preserve them make sure that
      noexpand is set (e.g. SET s={ 'a' 'b' 'c'} ).



      The output from this programme is passed to a second stage of lexical
      analysis. This passes integers and floats through unaltered, while
      words are passed through a filter to see if they are external
      tokens(26)
      from the grammar (such as CONNECT).
      If a word is recognised as being a token then that token is returned,
      otherwise the token WORD is passed, and the text of the word is stored.
      Tokens may be written in
      either lower or upper case, but for clarity they are written in upper
      case in this document. The overloading of lowercase tokens is achieved
      at this stage by simply refusing to recognise them as keywords.



      The input stream is now fully analysed into tokens and is passed to the
      parser, which is written in YACC.
      If the sequence of tokens seen corresponds to a grammar rule,
      the parser executes the appropriate section
      of code, which is written in C. If the parser doesn't understand, it
      tells you that you have a syntax error and prints the last
      logical line that it was processing, with the error underlined. If you can't
      figure out which command it really failed on, try setting the VERBOSE
      flag to be 4 or more. This produces a voluminous output, which will stop
      suddenly when the error re-occurs.
      One simple rule in the grammar is that a WORD should be
      treated as a possible macro.

      Peculiarities of the Grammar




      If the command interpreter is faced with a pair of grammar rules such as

              AA BB CC
      and
              AA BB
      


      it may not know whether to treat the tokens AA BB as the first part of
      AA BB CC or as the complete command AA BB followed by the token
      CC beginning the next command
      without examining the next token. This ambiguity only arises if a command can
      begin CC, and may
      be dealt with by defining the second rule as

              AA BB \n
      


      This should be borne in mind whenever
      SM complains about a syntax error in an apparently valid command (such
      as LIST MACRO HELP, intended as first LIST MACRO and then the valid
      command HELP). The presence of a required carriage return also sometimes
      requires that macros be spread over a number of lines rather than as one
      long list of commands, although a carriage return may always be written as
      `\n', which makes SM think that it has found a carriage
      return. There is a also requirement that an ELSEless IF statement
      should end with a newline; this is produced by a subtlety of the way
      that IF's are processed and is discussed under IF.



      SM places a restriction upon commands such as RELOCATE which
      expect more than one argument, which is that the arguments must be
      numbers rather than (scalar) expressions. This is required by the
      unary minus, as if the grammar sees expr1 - expr2 it cannot know
      whether this is the two expressions expr1 and -expr2, or the single
      expression expr1-expr2. Unless the grammar is changed, for instance by
      using commas to separate arguments, this restriction cannot be lifted;
      it can, however, frequently be circumvented using macros such as rel

      discussed under `Useful Macros'. As an alternative, in almost all
      cases the expression can be enclosed in parentheses, for example
      connect (lg(x)) (-lg(rho)).

      The Macro Processor




      Executing a macro consists of substituting the text of the macro for
      its name. In order to understand how SM does this you have to
      know a bit more about how it processes input characters. We said above
      that it `passed the whole line' to the lexical analyser. What it
      actually does is to pass a pointer to the line, and starts reading
      from the beginning of the line. Now if you execute a macro, all that
      is done is that we now pass a pointer to the text of the macro, and
      start reading from it instead. The old pointer is pushed onto the top
      of a stack. When SM comes to the `\0' at the end of the macro
      text, the stack is popped and input continues as if the macro had
      never been seen. When we come to the end of the `whole line' pushed at
      the top of this paragraph, it is popped, and SM gives
      you a prompt for more input.
      Of course, if a macro had been seen while the first
      macro was being executed, the first one would get pushed onto the
      stack, and attention transferred to the the new one. If a macro has
      any arguments, their definitions are pushed onto an argument stack
      which is popped at the proper times. To jump ahead a little, variables
      are implemented in a very similar way, being pushed onto the stack, as
      are DO and FOREACH loops, and perhaps more surprisingly

      IF statements.



      The strange behaviour of RETURN at the end of macros comes about
      because when the input routine is reading the RETURN it has to
      read one character beyond it, so as to know that it isn't dealing with,
      say, RETURN_OF_THE_NATIVE. But in looking for the next character
      it has to pop the macro off the stack, so when the RETURN is
      acted upon we have already returned from where we wanted to
      return from, and we now RETURN from the wrong place. In a
      similar way, an IF at the end of a macro will cause the parser
      to look for an ELSE, thereby popping the macro stack if there
      isn't one. If the IF test was true, and contained references to
      macro arguments, there will be a problem as either there will be no
      macros defined, or the arguments to the previous macro on the stack
      will be supplied.



      This behaviour is changed in SM2.4.3 and above; an automatic
      space or newline is added at the end of every macro, avoiding this problem.



      Macro definitions are currently stored in the form of a weight-balanced
      tree (actually
      a
      tree). This means that the access time for a given macro
      only grows as the logarithm of the total number defined. In the future it may
      be possible to choose the weights depending on the access probability for
      a given macro, but this is not currently possible. Definitions of variables
      and vectors are stored in the same way.

      The DO, FOREACH, and IF commands




      It seems worth discussing the implementation of these commands.
      Both loops consist of a definition of a variable, together with instructions
      about what to do with it, followed by a list of commands within a set
      of {}, while IF just has the command list.
      It is not possible for the main grammar to execute commands or
      macros, as the YACC implementation is
      non-reentrant, so the best that it can do is to push the commands onto
      the input stack as a sort of temporary macro, after defining the
      initial value of the loop parameter. When the `\0' at the end of the
      loop appears, instead of popping the macro stack we simply define the
      loop parameter to have its next value, and jump back to the
      beginning. This means that you can't change the value of a loop parameter,
      as it'll be reset anyway, but you can use it as a sort of local variable.



      IF statements are similar, in that we read the entire list
      before executing it. Once more, a temporary buffer is pushed onto the
      stack, with instructions to delete it after use. The reason that a newline
      is required after an ELSEless IF is that the grammar will
      have already read the next token to see if it was ELSE. If it
      wasn't, then it will seem to have been typed before the body of the
      IF. For example, IF( test ) { echo Hello } PROMPT : will be
      parsed as IF( test ) { PROMPT echo Hello } : if test is true,
      but correctly as IF( test ) { echo Hello } PROMPT : if it is false.
      Because an extra \n does no harm, we demand it.

      Examples of How SM Parses Input




      If you want to watch SM thinking about these examples, the command
      VERBOSE 4 will make it print out in detail each token as it reads it,
      and each macro or variable as it expands it. To turn this off, use
      VERBOSE 0 or VERBOSE 1.
      To really see the parser at work, try a negative value of verbosity.
      This will report every step that the parser takes, providing that it
      was compiled with DEBUG defined. A second negative value will turn the
      information off again.


      PROMPT @

      PROMPT is an external token, so PROMPT is passed to the
      grammar which recognises the rule
      PROMPT WORD, and sets the prompt to be `@'. When it has finished,
      control is passed back to the input routine.
      MACRO p { PROMPT }


      This is a simple macro defining p to be PROMPT
      p @

      The lex analyser doesn't recognise p as a keyword, so it returns
      WORD
      and as the grammar has no other interpretation of a WORD in this
      context,
      it passes p to the macro interpreter, which
      replaces it by PROMPT (i.e. pushes PROMPT onto the input stack).
      SM now thinks that you have just typed

      PROMPT @, and behaves as described in the first example.

      MACRO pp 1 { PROMPT $1 }

      The macro pp is declared to have one argument, which is referred to as
      $1. After pp is invoked it reads the next (whitespace delimited) word
      from the input stream, and replaces $1 by that word.
      pp @


      Just like the first example, the prompt is set to @.
      pp

      You are prompted for the missing argument to PROMPT.
      PRMPT

      As PRMPT isn't an external token, it is a WORD, so SM
      tries to execute
      it as a macro and complains if it isn't defined.

      DEFINE Hi Hello

      The variable Hi is defined to have the value Hello.
      WRITE STANDARD $Hi Gentle User

      When it has read $Hi SM pushes the value of the variable Hi

      onto the stack and then reads it, popping it off again when it has finished.
      The WRITE STANDARD command writes Hello Gentle Reader (i.e.
      up to the end of the line) to the terminal.

      WRITE STANDARD $Hi Gentle User \n pp "SM>"

      As above, the rest of the line is written to the terminal (up to the
      carriage return `\n'), then the prompt is changed yet again.

      The Stdgraph Graphics Kernel


      SM can use a single set of subroutine calls to plot on almost any
      terminal, and on many printers. The routines that it uses, called stdgraph,
      were originally
      taken from the IRAF GIO package written at
      Kitt Peak by Doug Tody(27)
      and converted to C and partially re-written to be integrated into SM.
      Despite our extensive rewrite, these routines should probably still be
      considered to be in the public domain.

    • Graphcap Colours: Using Colours with Graphcap
    • Modified Entry: How to Modify a Graphcap Entry
    • New Entry: Writing a New Graphcap Entry
    • Raster: Support for Raster Devices
    • Compiling: Compiling Graphcap
    • Graphcap Index: Index to Graphcap Capabilities
    • The Graphcap File


      Stdgraph uses a file called a graphcap file to specify the properties of
      terminals, in a way that is similar to the termcap facility of Unix. You
      don't have to know anything about termcap to read this section; you don't
      have to read this section unless you want to change the graphcap file
      to add a new device, to fix a bug, or to change the way that SM treats
      your plotting device. The name of the graphcap file is given by the variable
      graphcap in the environment file.



      A list of files to be searched
      in order may be given instead of a single graphcap file (up to a
      current maximum of three). The usual way to accomplish this is to
      add an entry

      +graphcap          /u/rhl/sm/graphcap
      


      above any other graphcap entries in your `.sm' file, which instructs
      SM to put `/u/rhl/sm/graphcap' first in the list of files, followed by
      any others that might appear, either in your file or in some other that
      the system provides (ask the person who installed SM where the default

      `.sm' file is; usually something like `/usr/local/lib/.sm').


      A graphcap file is a way of describing a terminal in a concise way, so a
      programme can discover which idiosyncrasies a terminal has without having
      to be recompiled. A graphcap file consists of a number of entries, one for
      each device supported, and to add a new terminal all that one has to do is
      to add another entry.
      It is also possible to define variables in graphcap files, which are used
      in SY entries.
      You can compile selected entries in the graphcap file, so as to
      improve access time for popular terminals. If this has been done, changing
      the graphcap file for one of these terminals will have no effect until
      it is recompiled, see section Compiling Graphcap for details.



      For a list of all the capabilities that SM uses see the index to
      graphcap at the end of this appendix.



      Some devices are not supported through stdgraph (graphics drawn to a
      SunView window would be an example), but they still appear in graphcap
      with a special entry (DV) giving the name of the appropriate hard-coded
      device driver.



      Each entry consists of a name for the device, followed by a list of
      aliases, followed by a list of fields, separated by colons. A \ may be used
      to continue an entry onto the next line, and lines starting with a
      # are comments (comment lines are permitted both between and
      within entries).
      As a rather complex example,
      the graphcap entry for a Tektronix 4012 reads:

      tek4010|tek4012|TEK4010|TEK4012|Tektronix 4010/2:\
              :ch#.0294:cw#.0125:co#80:li#35:xr#1024:yr#800:\
              :MC=^M:CL=^[^L:CN#6:GD=^X:GE=^[1^]:\
              :ML=^[(1$0)`($1)a($2)c($3)d($4)b($$:lt=01234:\
              :OW=^]^_:RC=^[^Z:SC=(,!3, & *, &+!1, & *, &+!2:\
              :TB=^]%t^_:VS=^]:\
              :xr#1024:XY=%t:yr#780:
      
      


      This is one of the longest entries in the graphcap file - all of the terminals
      which are Tektronix emulators explicitly include this entry, so they only
      need provide the capabilities that are different from the Tektronix. As an
      example, the entry for a Pericom reads

      pericom|Pericom:\
              :GE=^]:TB=^](2#7-!2)%t^_:\
              :tc=tek4012:
      


      The | separate the aliases, and the final field tc=tek4012 tells
      stdgraph to take all other fields from the entry for tek4012, given
      above. If you have specified a list of graphcap files, each will be
      searched in order for each :tc= continuation. If you don't want the
      search to begin again use TC, e.g.

      graphon|Graphon which claims to support lw:\
              :LW=:TC=graphon:
      


      if you had used :tc=graphon: this would have been recursive and
      illegal, but as TC doesn't restart the search it merely has the
      effect of adding (or in general, replacing) an capability in a
      preexisting graphcap entry.



      Control characters are entered as ^A, ^B, and so on (those
      are two characters, `^' and `A'). `Escape' may
      be represented as ^[, \E, or in octal as \033. Because the
      normal way of handling strings in C treats \0 as meaning
      `end of string' you can't simply put a \000 into a graphcap
      entry, instead write \377 and SM'll interpret it as \0. (If
      you need a real \377 enter \377\377).



      If a delay of so many
      milliseconds is required before the transmission of a string, it is given
      first (followed by a * if it is to be applied to each line
      affected). This leads to problems with graphcap entries that start with
      numbers, you must precede them with a space or (if the string is run through
      the encoder) insert a no-op e.g. :CP=()1000:.
      Numerical values are preceded by a #, so :co#80: means that co
      (the number of columns
      displayed) is 80, while :MC=^M: means that MC (the cursor
      delimiter) consists of the character ^M. This could
      just as well have been written :MC=\010:. If the first character of
      a capability is `@', it specifies that that capability is not present for that
      terminal (e.g. :lt@=1234: specifies that lt is not defined).
      A field may simply not be provided if it is irrelevant, although in this
      case it may be supplied by a tc or TC continuation.


      A common set of graphcap entries to `comment out' are TB and
      TE, which deal with hardware character sets. If you don't want
      your plotter to use it's internal fonts simply insert `@' before the `='.
      By inserting their private file before the system one in the list of
      graphcap files, users can tailor the entries to their liking.



      We use a subset of the graphcap capabilities defined by the IRAF group, and the
      distinction between upper and lower case parameters comes from them. In a few
      cases our usage is different from theirs, in these cases we have
      specified our own capabilities
      (CD
      MC,
      DD
      SY,

      LT
      ML, and
      TS
      TB.
      We have also added the lt, BP, BR, CO, CS,

      CT, DC, DT, DV, EP, ER, and TC.
      capabilities.).
      First the lower case, which specify mostly dimensions:

      ch


      Height of a character, relative to the screen height being 1.0.
      co

      Number of columns displayable, with characters of width cw.
      cw

      Width of a character, relative to the screen width being 1.0.
      li

      Number of lines displayable, with characters of height ch.
      lt

      Which linetypes are supported in hardware.

      pc

      Pad character for delays (use NUL if not supplied).
      xr

      x dimension of plotting device. This may be specified as an argument from
      the DEVICE line. E.g. for DEVICE example 1200 1400,
      :xr=$1:yr=$2: is equivalent to :xr#1200:yr#1400:

      yr

      y dimension of plotting device. See the previous entry for an example.


      Of these, co and li are not currently used.








      The capitalised capabilities mostly tell
      the stdgraph routines how to plot lines, clear the screen and so forth. Some
      of these are no more than character strings to send to the terminal,
      (e.g. CL to clear a screen), but
      some use the graphcap entries to programme a sort of RPN calculator, which
      computes the bit-patterns that the terminals demand. This calculator is usually
      referred to as the `encoder'.
      We'll first list all the capabilities in a reasonably ordered way,
      then describe the encoder and what it can do,
      and then go through a number of examples.



      First the fields which are simple character strings to be written to the
      terminal.
      The second
      column is an attempt to explain the etymology of the two character name.

      CL (CLear)


      Clear the screen, possibly also the text screen.
      CW (Close Workstation)

      Close terminal, expect no more graphics.
      DS (Draw Start)

      Prepare the terminal to draw a line.
      DE (Draw End)

      Finish a line.
      FD (Fill Draw)

      Draw a side of a filled polygon.

      FE (Fill End)

      Finish drawing a filled region.
      FS (Fill Start)

      Start drawing a filled region.
      GD (Graphics Disable)

      Return the terminal to a character mode.
      GE (Graphics Enable)

      Set the terminal to graphics mode.

      IF (Initialisation File)

      Used to supplement OW if sequence is too long.
      LR (Load Registers)

      (Used by the RPN encoder, see `binary encoding').
      ME (Mark End)

      Finish a series of dots movements.
      MS (Mark Start)

      Start a sequence of dots movements.
      OW (Open Workstation)


      Prepare a terminal to produce plots.
      OX (Open workstation)

      (a continuation of OW).
      OY (Open workstation)

      (a continuation of OX).
      OZ (Open workstation)

      (a continuation of OY).
      PG (PaGe)

      Start a new page.

      VE (? End)

      Finish a series of pen (beam) movements.
      VS (? Start)

      Start a sequence of pen movements.




















      For hardcopy devices PG should start a new page.
      The GD and GE are used by terminals which spend some of their
      time being graphics terminals, and some being regular text terminals.
      The various "... Start" and "... End" capabilities assume that the
      points in question are specified by the XY entry (except for

      FS/FE where FD is used instead). Typically, the
      `start' is used to put the device into (e.g.) line-drawing mode, then
      the line is drawn with a sequence of XY's, then it is taken out
      of (e.g.) line mode with the `end'. The support for filling areas
      assumes that a region is specified by drawing a line around it; if
      this isn't so, you'll have to omit area fill from graphcap, and rely
      on SM emulating it for you. An example would be a Graphon
      GO-250, which has an area fill where you fill rectangular areas by
      specifying opposing corners; this is not acceptable to SM.



      Some operations require an argument, for instance setting the hardware line
      type, specifying which cursor to read(28), or specifying
      coordinates. In the following properties, the expected parameters are listed
      after the field names, the first to go into register 1, the second into
      register 2, and so on. If you haven't skipped forward to the section on the
      encoder this will seem obscure, but all will become clearer.

      CO(r,g,b) (COlour)

      Set next colour to (r,g,b).
      CS(n) (Colour Start)

      Start defining n colours.
      CT(i) (Colour Type)

      Set a colour.
      DC (Default Colour)

      Set default colour.
      LW(f) (Line Weight)


      Set the lineweight to f.
      MC(i,x,y) (sM Cursor)

      Decode a cursor response.
      ML(i) (sM Line)

      Set the linetype to i.
      RC(c) (Read Cursor)

      Read the cursor. `c' is for compatibility.
      SC (Scan Cursor)

      Decode the cursor reply following a RC.

      TB(x,y) (Text Begin)

      Start writing text at (x,y).
      TE (Text End)

      Stop interpreting characters as text.
      XY(x,y) (X Y)

      Encode the coordinate pair (x,y).













      Some of the above comments are a little cryptic, but we return to the
      various graphcap parameters that take arguments as examples after describing
      the encoder. Note that it isn't sufficient to change the
      ML entry -- for a linetype to be supported in hardware it must also be
      included in the lt list, e.g. lt=01234. Similarly, for hardware
      fonts you must include ch and cw, and TB must be present
      even if it does nothing. Note that LW is passed a floating point number,
      and that the special case 0 is special, meaning choose the most efficient line
      thickness for the device.



      The following capabilities have to do with rasterising and are
      discussed in their own section near the bottom of this appendix:

      BP (Bit Pattern)

      Bit patterns for rastered data.
      BR(i) (Begin Row)

      Begin row of rastered data.
      EP (Empty Pattern)

      Bit pattern for rastered empty pixel.

      ER (End Row)

      End of a row in rastered data.
      ll (lINE lENGTH)

      Length of a row for DR=hex.
      MR (Many Rows)

      Number of rows output at once.
      nb (nUM bYTES)

      Number of bytes to process at once for MR.

      RA (RAster)

      (RA is no longer supported -- see DV).
      RD (Raster Device)

      Type of device if not generic.










      Raster devices also make use of xr, yr, CW, OW,
      OX, OY, OZ,

      OF, and SY which are also used by stdgraph itself.



      Finally there are some capabilities that are designed for driving
      hardcopy devices and devices that may not use stdgraph at all:

      DT (Device Type)

      Type of device in use.
      DV (DriVer)

      Name of hard-coded driver.

      OF (Out File)

      The file to direct output to.
      RT (Record Terminator)

      (RT is no longer supported).
      SY (SYstem)

      The action to be taken upon closing the OF file.






      The OF file may be specified with the last characters being `XXXXXX', in
      this case the Xs are replaced by a random characters, to make a unique
      filename. If the variable temp_dir is defined in the environment
      file, then OF is created in that directory, otherwise it is put in the
      current directory. The DT string, if present, specifies the type
      of device in use. Currently the values are only used under VMS, where
      they are used to decide how to open files. The recognised values are
      "qms" and "imagen". In general DT should be omitted, as it
      requires programming support, but it can help stdgraph to deal with
      hostile operating systems. For a discussion of the DV

      entry, See section New Devices and New Machines.



      The SY string is passed to the operating system after graphcap
      variables have been expanded (they are similar to macros in Unix's
      make). A variable is defined with a line like:

      	name = value
      

      where name must start in the first column. Any white space surrounding
      the equals sign is removed, as are any trailing blanks. If value starts
      with a $ it is taken to be a regular SM variable.
      Variables may be defined in any of the graphcap files in the search path,
      and if a name appears more than once the first value
      found will be used (if you change graphcap without leaving SM the variables
      are re-read). There is no guarantee that all the graphcap files in the
      path will be read but this is unlikely to be a problem.
      The major use for graphcap variables is probably for encoding
      rasterise's full name:

      BIN = /usr/local/bin
      device|some device:\
              :DV=raster:OF=tst_XXXXXX:\
                 ...
              :SY=${BIN}/rasterise -r $0 $F $1:
      


      Variables are written as ${name} not $name, which
      means that they will not (usually) conflict with the operating system's
      uses for dollar signs. The graphcap variable F is special, as it
      always expands to the filename specified as OF. As a
      concession to history it may be written as $F instead of ${F}.
      Also special are $"prompt", which is replaced by a string read from the
      keyboard (you are prompted with prompt),
      and $n which is replaced by the n'th argument to the DEVICE

      command.
      For example, if the DEVICE command were DEVICE qms lca0 Hello
      (or DEVICE 1 qms lca0 Hello), then
      the device name qms would be $0, lca0 would be $1 and
      Hello $2.
      If a `$' is found under other circumstances it is simply treated as a dollar
      sign, but if you wish you can escape it with a \ (but remember that
      the \ must itself be escaped so to explicitly
      escape a dollar in an SY string you must type \\$).
      This means that (under Unix)
      you can access environment variables from SY strings, e.g.

      :SY=mv ${F} $HOME:. If a variable is referenced but no value is
      provided when the device is opened a warning message is printed; this
      message can be suppressed by referring to the variable as (e.g.)
      $%1.

      The SY string is only used if an OF file has been specified. There is no
      guarantee that SY is supported by all operating systems, but it is certainly
      available under Unix and VMS (SY requires the C call `system()', as defined
      for Unix. We have provided one for VMS, and any serious SM
      implementation would have to have one too.)
      A trivial example of SY in use on an Unix system would be:

      :SY=cat $F ; rm $F:OF=out_XXXXXX:
      


      (cat prints a file, ; separates multiple commands on a line,
      rm deletes a file). Because not all operating systems can support
      multiple commands on one line, you can use \n within a SY string to
      separate commands. For example, under VMS that SY string could have been
      written

      :SY=type $F. \n delete $F..*:OF=out_XXXXXX:
      


      (Type adds a `.lis' unless explicitly given a closing `.', delete
      requires a version number, hence the $F. and $F..*.)
      An example of the use of $"" would be

      :SY=mv $F $"Output filename? ":
      


      which renames the OF file to whatever you want.



      The RT capability has been deleted in version 2.0, in favour of
      using DT; The RA capability has been replaced in version
      2.1 by :DV=raster:.

      Stdgraph's Binary Encoder


      Different terminals have very different ways of doing the same thing. For
      example to move the beam to (200,200), a vt240 in REGIS mode needs to be
      told `[200,259]', while a Tektronix 4010 needs `&h&H'. In order to cope
      with this much diversity, stdgraph has a binary encoder with a 50 element
      stack, 10 registers and about a dozen operators. The encoder communicates with
      the rest of the world through its registers - for example in encoding a
      coordinate pair it expects to find x in register 1, and y in register 2. When
      reading a graphcap string, initially stdgraph simply copies the input
      characters to an output string, which is then written to the terminal.
      This is exactly what it does when it interprets the OW string
      for a Tektronix, OW=^]^_. However, in addition
      to characters such as ^ being special, it also recognises the
      following as being special:

      '

      escape special meaning of next character
      %

      Begin a format string
      (

      Switch from copy into encode mode.


      When in `encode' mode, the following operators are available:

      '

      Escape next character (recognised everywhere)
      %

      Formatted output, e.g. %d, %g, or %t
      )

      Revert to copy mode
      #nnn

      Push signed decimal number nnn onto the stack
      $


      Part of a switch statement
      .

      Pop a number from the stack, and put it in the output string
      ,

      Get next number from input string, and push it onto the stack
      `str`

      Prompt with str, then read a character and push it onto the stack
      &

      Modulus operator (similar to an AND of the low order bits)

      +

      Add (similar to OR)
      -

      Subtract (similar to AND)
      *

      Multiply (a left shift if number is a power of 2)
      /

      Divide (a right shift if number is a power of 2)
      <


      Less than (0:false, 1:true)
      >

      Greater than (0:false, 1:true)
      =

      Equals (0:false, 1:true)
      ;

      Branch, <boolean><offset>; (; is at 0 offset)
      0-9


      Push register 0-9 onto the stack
      !N

      Pop the top of the stack into register N.
      !!

      Pop the stack, and delay that many milliseconds.
      |

      Convert the top of the
      stack from float to int (it is rounded rather than truncated).

      Unless otherwise specified the stack is taken to be integer-valued,
      although in fact it can support either integer or floating point
      values. There is no type checking -- if you ask the encoder to print
      the top of the stack as a float, but you stored an int, you can expect
      trouble. If it is needed we might add more floating point support;
      apart from printing the top of the stack, the only floating
      point operation supported is `|' which rounds the top of the stack
      (taken to be a float), converting it to an integer (so, for example,
      1|1! converts the contents of register 1 from float to int).



      All the binary operators operate on the top 2 elements of the stack, and
      push the answer onto the top. Any other character is interpreted as an
      integer, and pushed onto the stack - for instance, `@' is the same as `#64',
      octal 100. A blank is the octal constant 040.



      The % command means, `format the top of the stack, and write
      it to the
      output string'. The format string may be any printf format specifier (printf
      is the C formatted i/o function. In practice, the only formats that you are
      likely to need are %c, %d, %g and %t -- and

      %t isn't even in C!
      %c means `write the integer as a character', %d means
      `format the number as a decimal integer', %6d means
      `and make it fill 6 characters', and %g means format a floating
      point number.
      If you should need to know more, look at any book on C.) The special format
      %t means `take x and y from registers 1 and 2, and format them for a
      Tektronix'. As we shall see below, you can programme the encoder to do this,
      but Tektronix emulators are so common that %t is provided for
      efficiency's
      sake. In fact there are two Tektronics formats, %t for 10 bit addresses,
      and %T for 12 bit addresses.
      The switch and branch instructions are discussed below, while examining
      specimen ML and SC strings.

      Examples of Graphcap Entries


      As a simple example, the ANSI command to set a non-graphics cursor to a
      given line and column is

      ^[[ line ; column H
      


      Assuming that the x and y coordinates are in registers 1 and 2 respectively,
      the corresponding graphcap string would be

      "^[[(2)%d;(1)%dH"
      


      (where the quotes are not part of the format.) What if line and column
      coordinates start at 1, but the terminal wants them starting at 0? then
      the format would be

      "^[[(2#1-)%d;(1#1-)%dH"
      


      You could write those #1's as ^A which would be slightly
      faster, but why bother?



      As promised above, it is also possible to encode Tektronix-type coordinates.
      The desired bit format for a 10-bit address is

      0 1 ya y9 y8 y7 y6
      1 1 y5 y4 y3 y2 y1
      0 1 xa x9 x8 x7 x6 
      1 0 x5 x4 x3 x2 x1
      


      where x1 is the least significant bit in x, and ya is the tenth bit in y.
      If x and y are in registers 1 and 2, the simplest XY (move/draw to
      (x,y)) string is

      "%t"
      


      but if this weren't available the following string would work:

      "(2 / +.2 &`+.1 / +.1 &@+."
      


      (as before, the double quotes don't belong to the format). To understand this,
      First look
      up the octal values of ` ' (040), "' (0140), and `@' (0100). Then the first
      `(' puts the encoder into encode mode. `2 /' pushes the Y value
      onto the
      stack, and right shifts it by 5 bits (` ' is 100000 in binary). The next
      ` +.' adds the resulting bit pattern `0 0 ya y9 y8 y7 y6' to 0100000 and
      transfers it to the output string, and we have produced the desired first
      byte. The other bytes are produced in a similar fashion.



      As another example consider an AED512, which is reputed to desire the bit
      sequence

      xa x9 x8 yb ya y9 y8
      x7 x6 x5 x4 x3 x2 x1
      y7 y6 y5 y4 y3 y2 y1
      
      


      The graphcap string

      "(#128!919/^N*29/+.19&.29&."
      


      will accomplish this. We could further optimise this by loading the value
      `#128' into register 9 once and for all with the LR capability, so a part
      of the graphcap entry would appear as

      ":LR=#128!9:XY=(19/^N*29/+.19&.29&.:"
      


      I've never seen an AED512, but this should work anyway.



      The switch instruction has the form

      $i ... $j-k ... $l ... $D ... $$
      


      where i, j, k, and l are integers.
      The encoder pops the top value off the stack adds `0' to make it
      a character, and scans forward looking for a $ followed by that
      character.

      $2-5 would match the characters `2', `3', `4', or `5'. When it
      has met its match, it executes the instructions that it meets until it
      reaches the next $ in execute mode. The encoder then skips forward
      until just after the
      $$, and resumes scanning. If the character from the stack is not
      matched by
      any of the cases, the encoder will use the $D (i.e. default) case,
      if present.



      As an example, consider how stdgraph sets the type of line to draw.
      SM expects linetype 0 to be solid, 1 to be dotted, and so on.
      We expect a linetype in register 1 and have to do something with it.


      For a Tektronix, the linetypes are set by an ML entry:

      ML=^[(1$0)`($1)a($2)c($3)d($4)b($$
      


      What does this do? The ^[ is simple, it is executed in copy
      mode, and writes the character ^[ to the output string.
      The (1 enters encode mode, and places the contents of register 1, the
      desired linetype, on the stack. Then begins the switch. If the linetype is
      0, then the encoder scans past the $0 and starts reading the string
      again with )`. The ) takes the encoder back to copy mode,
      so it copies ` to the output string, and encounters a

      ($ which puts it back into encode mode. Once in encode mode it
      recognises the $ as the end-of-case, and scans forward until it reaches
      $$, where it stops. We deduce that the set-linetype-0 escape sequence
      is ^[`. If register 1 had contained a 2, after
      entering the switch the encoder would have scanned forward to $2
      (ignoring
      all characters as it went), and copied c to the output string.


      If you want to support erasing of individual lines (LTYPE ERASE or
      LTYPE 10) you'll have to include a $\: case in your switch
      (as : follows 9 in the ascii character set, and an un-escaped
      : would end the graphcap entry). You'll have to escape the :

      in the lt list as well. When leaving erase mode, by specifying any
      other line type, the device will first
      be set to LTYPE 11 (i.e. ML'll get a ;) before it's
      set to the desired
      LTYPE; this gives the driver a chance to reset itself. It's wise
      to also turn off
      erase mode when closing the device. An example of an entry supporting
      erasing lines is a graphon, which includes

      :lt=01234\:;:CW=^[1^]^[^A^[2\
      :ML=^_^[(1$0)`($1)a($2)c($3)d($4)b($\:)`^[^P($;)^[^A($$:
      


      as ^[^P puts a graphon into erase mode, and
      ^[^A takes it out. Note that in erase mode the
      linetype is set to solid (^[`), so as to erase all types of lines.



      There is also a branch instruction, which has syntax

      <boolean><offset>;
      
      


      If the boolean is true (non-zero), then skip (offset - 1) characters in the
      programme
      string. The offset may be either positive or negative, and the `;' is at
      offset 0. For example,

      (0#15;)Goodbye(#1#8;)Hello()\n
      


      will print `Goodbye\n' if register 0 contains zero, or `Hello\n' otherwise.
      As an example of the use of `;', consider using the
      encoder to decode a string.
      Remember that `,' meant `read a
      character onto the stack', and that there was a graphcap capability SC to
      decode cursor responses. Suppose that we are dealing with a vt240 in REGIS
      mode, then a cursor read will return a string of the form `k[nnn,mmm]' where
      `k' is the character you hit, and (nnn,mmm) is the cursor position. We want
      to put k into register 3, and (x,y) into registers 1 and 2. This is a little
      messy, as we'll have to convert the ascii positions into integers. The desired
      graphcap entry is

      SC=(#0!1#0!2,!3,#0!8,#48-!99$0-91#10*9+!1#1!8$$8#1=#-39;\
      0!8,#48-!99$0-92#10*9+!2#1!8$$8#1=#-39;62-!2):
      


      The first part is simple enough, store 0 in registers 1 and 2, store the
      first character in register 3, read a character (the [), and store 0 in
      register 8.
      Then we come to ,#48-!99$0-91#10*9+!1#1!8$$8#1=#-39;.
      The ,#48- reads a character and converts it to an digit (48 is the
      decimal
      code for `0'), then stores it in register 9. The switch then checks if we do
      have a digit, if so we multiply register 1 by 10 and add the new digit. We then
      set register 8 to 1 and finish the switch which is here being used as an
      if statement. The 8#1=#-39; tests register 8 against 1 (i.e. checks if
      we found a digit), and if we did it jumps back 39 characters, to read the
      next character(29).
      So we are accumulating the integer nnn in register 1, just as we needed to.
      The rest of the string deals with decoding the y coordinate.



      Sometimes you don't want to read from the input string, but from the
      keyboard instead. In this case use `str`, e.g.
      (`Hello\: `#48-$0)False($D)True($$)\n: will prompt you with
      Hello: , then read a character from the keyboard. If you enter
      a `0' it'll print False, otherwise it'll print True. Of course,
      in reality you'd want to do something more useful (such as erasing
      the screen).

      Using Cursors with Graphcap




      We have just been through a long explanation of how to decode a cursor string,
      but how did stdgraph know what to read in the first place? After receiving the
      RC string, the terminal will send back a sequence of bytes, and the format
      of these bytes must be specified in graphcap.(30)
      There are two ways to do this,
      either by specifying a sequence of characters which `end' the response
      string
      along with a minimum number of characters to read, or by specifying a pattern
      that the terminal response is to match. A typical example of the former is a
      Tektronix whose cursor response may be chosen to be control-M
      (this is
      called the GIN response, and can usually be set in the terminal setup). We
      know that the terminal will also send 5 other bytes (the key struck and the
      encoded x,y coordinates so we would specify

      
      :MC=^M:CN=6:
      


      On the other hand, a REGIS terminal sends `k[nnn,mmm]'. This can be specified
      as

      :MC=?[#*,#*]:CN=-6:
      


      where the negative value of CN means that we are providing a pattern not just
      a terminator (as before, the absolute value of CN is the minimum number of
      bytes in a cursor response). In MC strings, but nowhere else, the characters
      ?, #, and *

      are special (although their special meanings may be escaped with
      a \). ? will match any character, # any digit, and
      * means `match zero or more of the preceding characters'. So a MC
      string of
      a#*?ba will match `aaa1111bbaa' at the third character. (Incidently,
      a#*?a would match at the first). Because this special character syntax is
      different from that used in standard graphcap files for IRAF, the name of
      this graphcap parameter has been changed from CD to MC.



      If your cursor is attached to a mouse, if possible the buttons should
      be set up to generate
      `e', `p', and `q' from left to right (if you have that many buttons).
      If you have only one button, `p' is probably the best choice.

      Using Colours with Graphcap


      The number passed to CT are the same as those specified with the
      CTYPE INTEGER command, so initially they specify
      default, white, black, blue, red, green, magenta, yellow, and cyan
      (white is 1).
      These are the colours corresponding to turning one, zero, two, or three of the
      primary colours on. The default colour to use for a device is
      specified by the DC capability, e.g. :DC="red":.



      The CS and CO capabilities are used to support the CTYPE = expr command. First CS is used to tell the device how many
      colours to expect, then CO is used for each number, with red, green,
      and blue as its arguments. In this case CT passes an index
      into the set of CO values. If you want to get an index, but
      don't need CS and CO, you must still provide them; just
      provide a no-op such as :CS=():.


      How to Modify a Graphcap Entry






      You might think that all that you have to do to modify a graphcap entry is
      to start up your favourite editor, and start typing. You could do that,
      many people have, but it isn't recommended because you'll have to do it
      again when a new release of SM comes along. It's better to use SM's graphcap
      search path (see section The Graphcap File) as follows:



      Let us assume that you want to modify the xterm entry to print something
      every-time that is changes from graphics to alpha mode or vice versa (why?
      so as to fix a problem with excessive screen switching). First
      set up the system `.sm' file to look like:

      +graphcap               /my/private/graphcap
      graphcap                /usr/local/lib/sm/graphcap
      


      which tells SM to first search `/my/private/graphcap'
      then `/usr/local/lib/sm/graphcap' (the graphcap file that we provide)
      for graphcap entries. Then edit `/my/private/graphcap'

      and add the entry

      xterm|an xterm with noisy mode flipping:\
              :GE=\nE\n^[[?38h:GD=^[^C\nD\n:TC=xterm:
      


      Note the use of :TC=xterm: which says that SM should skip this file
      when looking for the definition of xterm, thus avoiding an infinite
      loop.



      When a new version of SM is released your new definition will continue
      to work (unless we change the definition of xterm in which case
      you'll have some work to do anyway). You can use this technique to change
      entries or add your own new ones without modifying the system file; all
      of your changes are in `/my/private/graphcap'.

      Writing a New Graphcap Entry





      So, if you're faced with a new piece of hardware what should you do?
      First of all, don't panic -- writing entries is quite simple. Second,
      see if your device is basically the same as one that already exists
      in graphcap, for example the entry for `graphon' uses the `selanar'
      entry, and it in turn uses `tek4010'. You might be able to get away
      with using tc to satisfy most of your device's needs.



      Before writing your new entry please read the previous section to learn
      the recommended strategy for modifying graphcap files.


      Let's assume that you are faced with a totally new type of device
      and really do have to start from scratch. First find out how large
      your device is, and fill in the xr and yr entries. If you
      are going to use hardware character sets you also need ch and
      cw. Next decide on the string to initialise the device -- does
      it need to be set into some weird mode -- and put it into OW.
      Put the string to reset it into CW. Now, if the initialised
      device needs to be put into a special graphics mode put it into GE

      and its inverse into GD. Next, you need to tell SM how to
      draw a line and move the plot pointer. So enter the DS, XY,
      DE, VS, and VE capabilities. Of course, if one
      isn't required, don't put it in. If you have some sort of
      printer you probably want to store all the commands in a file (OF=), and to plot them (SY=). You should now be ready to make
      your first test, so plot a box. If it doesn't look right, fix it. Or you
      might like to try printing the cover (load cover cover).



      When all is well, you can begin looking into options that might make your
      graphcap entry more efficient. Look through this appendix to see what
      is available. Does your device support line types? Add
      ML and lt. Heavy lines? LW. Coloured lines or a
      cursor? See section Using Colours with Graphcap.
      Filled polygons? FS, FD, and FE. Dots? MS ME.
      Hardware characters? TS TE. If your device produces
      hardcopy you should arrange to start a new page with PG (the

      PAGE command).
      When you have finished please send us your new entry.

      Support for Raster Devices





      Stdgraph can only handle devices that can plot vectors specified by
      their endpoints; unfortunately some devices (such as most line
      printers) can only plot graphs when they have been reduced to rows of
      `on' and `off' pixels. SM supports such devices through
      DEVICE raster and a separate programme called rasterise.
      You specify that a device in a graphcap file is a raster device by
      using DV: :DV=raster: (The old form :RA: is no
      longer supported).
      It communicates with the rasteriser through graphcap, so the whole
      process is user transparent. A separate rasterising programme was
      written so as to allow the plot to be produced in the background while
      you do more productive things, and to allow the rasterising to be
      done on a remote machine.



      DEVICE raster produces a file, whose name is specified as usual
      by the OF field in graphcap, containing the vectors to be
      plotted (as groups of four short integers) in device coordinates,
      where the size of the device is taken from xr and yr. When
      the device is closed, the command specified by SY are executed,
      and these will usually be of the form
      rasterise -r $0 $F outfile\n print_it outfile\n delete outfile

      where print_it is the proper way of actually getting a plot. Under Unix,
      the command might well be something like
      (rasterise -r $0 $F - | lpr -v -r -P$1)& dispensing with the
      temporary outfile.




      What do these rasterise commands do? The command syntax is
      rasterise [-flags] device infile outfile, where the infile may
      be specified as `-' to use standard input (sys$input to VMS),
      where the outfile may
      be specified as `-' to use standard output (sys$output to VMS).
      Possible flags are r to remove the infile after use, R to
      rotate the plot through 90 degrees, and v for more verbose operation.

      Rasterise then reads the data in the infile, and produces a
      rasterised version, row by row, on the outfile. In order to do this,
      it looks in graphcap for an entry for device, and uses the xr,
      yr, OW (and O[XYZ]), and CW fields
      as usual.(31)



      Let's first consider a simple, one-line-at-a-time device such as a line
      printer. Before writing each row to outfile, rasterise encodes
      the BR (Begin Row) capability, using the current row number as an
      argument, and encodes