Google
 

Trailing-Edge - PDP-10 Archives - decus_20tap1_198111 - decus/20-0002/comnd.mss
There is 1 other file named comnd.mss in the archive. Click here to see a list.
@device(xerox)
@make(manual)
@style(doublesided,bottommargin=0,linewidth=60,indent=5,spacing=1)
@pageheading()

@{{To get subentries in the index, the following is used:	}}
@{{If we want:							}}
@{{	A ...							}}
@{{	  B ...							}}
@{{	  C ...							}}
@{{	  D ...							}}
@{{  do the following at the appropriate places in the text:	}}
@{{	@index(A)						}}
@{{	@indexentry(key="A B",entry="@ @ B",number)		}}
@{{	@indexentry(key="A C",entry="@ @ C",number)		}}
@{{	@indexentry(key="A D",entry="@ @ D",number)		}}
@{{								}}
@{{The following indexentry commands are used to produce main	}}
@{{entries with no page numbers - they will have subentries.	}}
@indexentry(key="Variables",entry="Variables")
@indexentry(key="COMND Functions",entry="COMND Functions")
@indexentry(key="Procedure Parameters",entry="Procedure Parameters")

@skip(3 inches)@center(@b(SAIL-COMND Interface
====================)


Andrew R. Lowry
and
David S. Millman

Columbia University
Center for Computing Activities
User Services Group

@value(date))
@style(spacing=2)
@newpage
@Unnumbered(Preface)
@set(page=1)
@pageheading(center="SAIL-COMND Interface",left="@ref(page)",even,immediate)
@pageheading(center="@title(chapter)",right="@ref(page)",odd,immediate)

This document describes a package of SAIL procedures designed to make the
TOPS-20 COMND jsys easily available to the SAIL programmer.  All functions
of COMND are included, including provisions for up to ten alternate functions
in a single call.  @index(Unimplemented Features)
Two features of COMND which are not implemented are the
following:   @index(Reparse Dispatch Address)
A reparse dispatch address may not be specified in word 0 of
the command state block, and the cm!tbuild procedure for constructing TBLUK
lookup tables from string arrays does not make provision for declaring strings
as @index(Keyword Abbreviations)@indexentry(key="TBLUK Lookup Table Abbreviated Entries",entry="@ @ Abbreviated Entries",number)
abbreviations for other strings in the array (see the discussion of the
CM%ABR bit in the description of the CMKEY function call in the Monitor Calls
Reference Manual).

The document is in three parts.  The first part describes the COMND jsys itself
in moderate detail.  The second part describes the SAIL-COMND interface routines
and how to use them.  The third part gives some brief examples of the use of
the interface routines.

@index(Acknowledgements)
Many thanks go to Frank @w(da@ Cruz), Chris Ryland and Norman Kincl of the CUCCA
Systems Group, and to Ted Markowitz, Ken Rossman, Harry Yudenfriend and Jeffrey Slavitz of
the CUCCA User Services Group 
for their technical assistance and numerous suggestions.  Also thanks to
any others who used the preliminary versions of the package during its
development, for bearing with the many bugs and misfeatures and for any
contributions which they have made.
@Chapter(The Jsys)
@section(General Information)
	Every user of the DECsystem-20 quickly becomes familiar with the 
workings of the COMND jsys, although he may not be aware of his education.
The COMND jsys is the thing that figures out what he means when he abbreviates
his commands to the @index(EXEC)EXEC and finishes up his commands for him when he types
an escape character.  It is also what types guide words in parentheses
telling him what he must type next, and it is the thing that will untiringly
answer his question marks with lists of alternatives for him to choose from.
In short, it is one of the things that makes learning and typing in commands
to the EXEC as easy as it is.  Hence its name -- COMND.

@Section(How It Works)
	Using the COMND jsys mainly consists of the following:  you tell it what
you're looking for, and it tells you what it finds.  All the complexities have
to do with how this communication takes place.  A great deal of this is common
to all the calls you can give to COMND, but some of it depends on exactly what
you're asking COMND to look for.

@Subsection(Information Needed By COMND) 
	All the information which you must supply to COMND may be broken down
basically into two sets, the @index(Command State Block)@index(CSB)Command State Block (CSB) and the @index(Function Descriptor Block)@index(FDB)Function Descriptor Block
(FDB).

	The @index(Command State Block)@index(CSB)CSB is ten words (storage locations) long and contains information
about what has been typed so far,  how much more can be typed without overflowing
the space that has been set aside to store it, and where COMND can find other information
that it needs. Most of this information must be supplied only once by the
program using COMND, and from that point on COMND will update the information
as it goes.  Exact information on the contents of the CSB is not necessary
for the SAIL programmer who wants to use COMND, but for those interested, it
can be found in  the DECsystem-20 Monitor Calls Reference Manual.

	The @index(Function Descriptor Block)@index(FDB)FDB is four words long and contains information which is more
specific to the type of call which is being made than is the information in
the CSB.  It is here that COMND finds out what type of information it should
be looking for -- file name, time of day, one out of a list of possible
keywords, or any other of the 24 different items it knows how to look for.
Also in the FDB it finds pointers to a @index(Help Message)help string and a @index(Default String)default string which
the controlling program supplies.  The help string is what will be typed if
the user types a question mark, and the default string is what COMND will fill
in if the user types an escape character.  Finally, COMND finds several 
indicators in the FDB telling it how to process the request -- things like
whether or not to convert lower case input into upper case,  whether or not
to accept indirect file specifications,  etc.  

	The SAIL programmer who wishes to use the COMND interface need not
worry at this point how the information is stored in the FDB and the CSB.
He will simply supply the information as parameters to the package routines,
and they will take over from there.  Those who are interested, however, are
referred to the DECsystem-20 Monitor Calls Reference Guide.

	The only thing left to do after the CSB and FDB have been properly
filled in is to tell COMND where they are and let it go do its work.  

@Subsection(The Parsing Process)
	When COMND is invoked, it starts accepting characters from (usually)
the job's controlling terminal.  It keeps taking characters until the user
types what is called an @index(Action Characters)"action" chatacter.  Action characters include 
@index(Question Mark)question mark, @index(Escape Character)escape, @index(Control/T Character)ctrl/f and @index(Carriage Return)carriage return, and they are called action
characters because COMND won't start doing what it is supposed to do until
one of them is typed.  Once an action character is encountered, COMND will
determine whether or not the user has finished typing what he was supposed to
type, and if so, will return control to the calling program.  This can be done
in any of three possible states. 

	If COMND was able to interpret what was typed, and decided that it
was an appropriate response, then it returns normally with the data that
it received stored somewhere where the program can easily retrieve it. 

	@index(Parsing Errors)If COMND was unable to understand what was typed in the context of
what it was told it was looking for, then it will return with an error
indicator set so that the program will know that something went wrong.

	@index(Reparse)The third possibility is best shown by example.  Suppose a program
desires to obtain from the user first a file name, then a time of day.  This
will involve two calls to COMND.  When the first call is executed, suppose
the user (call him @index(Fred)Fred) types in FOO.BAR as his file name.  COMND accepts this as a valid
file name and returns normally to the calling program, which then executes
COMND again, this time asking for a time of day.

	At this point, Fred decides that he really didn't want to use FOO.BAR,
but wanted FOO.BAZ instead.  So he deletes back to the R and types in a Z, and
then he goes ahead and types in a time of day as required.  Now it looks like
trouble ... COMND has already told the program that Fred wanted FOO.BAR, and now
it needs some way to let the program know that he changed his mind.  In COMND
jargon, we say that a "reparse" is needed.  COMND sets a flag to let the
program know what has happened, and now the program must start right from the
beginning and reissue all the calls that it made to COMND for the current command
line (this rather vague term will be firmed up shortly).  Thus it redoes the
call to get a file name, and COMND fills in FOO.BAZ this time, and then
it continues with the time of day call just like before.  If there had been
other calls on this command line before the file name, they too would have
to be reissued in the same order as they originally were called.  This may
seem rather complicated, but with SAIL's block structure and its NEXT and
CONTINUE statements it all becomes fairly simple, as will be demonstrated in
Part III of this document.

@subsection(The Command Line)
	@index(Command Line)The term "command line" was used a few times in the preceeding
paragraph, and although it may have a fairly intuitive meaning, it also
has a very strict meaning in the context of the COMND jsys, which will be
explained now and should be kept in mind when trying to understand the
reparse mechanism.

	One of the calls that can be made to COMND is called
@indexentry(key="COMND Functions CMINI",entry="@ @ CMINI",Number)"CMINI" (each
different call has its own slightly mnemonic name).  The CM signifies that
it has something to do with COMND, and the INI stands for "INItialize".
This call, unlike the rest of the calls, accepts no input from the terminal.
It is used to set up initial values in the CSB and to type out the command
@index(Command Line Prompt)line prompt.  The end of this prompt is the farthest back that a user may
delete when using the program.

	A "command line", then, consists of all responses to COMND calls
made between successive CMINI's.  For a @index(Reparse)reparse, the program reissues COMND
calls starting with the one after the CMINI call that initiated the command
line.  The CMINI call should not be reissued.  That would be done if an @index(Parsing Errors)error
were detected and the entire command line had to be restarted.  The difference
is that when CMINI is done, COMND forgets everything that was previously
contained in the buffer.  This is appropriate for a complete restart after an
error, but not for merely backing up on a reparse.

@subsection(The Control/H Feature)@label(ctrl/hfea)
	It was explained in the previous section that when a parsing error
occurs during a call to COMND, a flag will be set and the calling program
should reissue all the COMND calls for the current command line, including
the CMINI.  When that is done, the user may retype all of the information
that he previously typed correctly, and then finish the command line.  

	Often,
however, this will mean that the user will have to retype quite a bit of
correct information.  This may be avoided by using the cm!retry procedure
as described above, but there is a safer way of going about things.  If
the program leaves the CSB in the correct state, then the user will have
the option of typing a contro/h (backspace)@index(Ctrl/H Character)@index(Backspace)
character as the very first character after the new prompt, which will
cause the previous contents of the command line to automatically be
retyped up to but not including the erroneous field.  All this can be
perfectly transparent to the calling program; although there is a way
for the program to find out that a ctrl/h was typed, it may ignore this
information and issue its calls exactly as if the user were typing everything
in again by hand.

	To find out how to adopt the ctrl/h feature in your SAIL
programs, see the description of the cm!ini procedure (section @ref(cm!iniproc), page @pageref(cm!iniproc)).

@Subsection(Multiple Function Calls)
	The only topic left to cover in Part I is concept of @index(Multiple Function Calls)multiple 
function calls.  This refers to giving COMND more than one alternative 
to look for.  For instance, it may be equally acceptable at a particular
point in a command line for the user to type either a date, or simply
a decimal integer, specifying possiblly a number of days from the current
date.  It would be advantageous for COMND to know about the alternatives
and not have to return an error if the second alternative were chosen.

	To accomplish this, it is possible to have several @index(FDB Chain)FDB'S all linked
together in a chain.  The first one contains a pointer to the second, which
contains a pointer to the third, etc.  Then if COMND can't make sense of
what is typed in the context of the first FDB, it goes on and tries the next
FDB, and so on right down the line until it gets to an FDB that does not point
to another one.  At that point, if none of the FDB's succeeded, an 
@indexentry(key="Parsing Errors With Multiple FDBs",entry="@ @ With Multiple FDBs",Number)error
condition is finally signalled and COMND returns.   If one of the FDB's
does fit, then not only is the normal data returned, but also the location
of the succeeding FDB so that the program will be able to determine what
ultimately happened.

	The same procedures apply to multiple FDB's as to single ones in
regard to reparsing, error restarts, etc.  Remember that when using multiple
FDB's only one input item is parsed, not several.  The multiple nature comes
from the fact that COMND is given several choices as to how it should attempt
to interpret that item.

	Note that when using multiple FDB's, only one CSB is used.  This fact
underlines the main difference between the natures of information stored in the
two blocks, the CSB being fairly call-independent, while almost all of the
information in the FDB depends on exactly what call is being made.
@skip(3)
	This concludes Part I of this document.  At this point you should have
an idea of what is involved in getting the COMND jsys to do your work for you.
You are not prepared to go out and use COMND in your assembler programs
(unless you have done some reading in other sources), but you should have
enough understanding now to be able to follow Part II, which goes into the
details of using COMND from SAIL programs.  

@chapter(The Interface)
	
	The information in this part describes the use of the SAIL-COMND interface.
This interface allows the programmer to implement the COMND jsys in his programs
in the form of a set of SAIL procedure calls.  The information which must be
stored in the CSB and FDB is passed in the form of procedure parameters, and
the procedures take care of storing them in their final form.  

	This part is broken up into three sections, the first describing 
conventions and procedures common to all COMND calls using the interface. 
The second section  describes each call in detail, indicating what information
must be supplied and what is returned.  The third section gives an overview
of how to implement multiple FDB's using the interface.

@section(General Rules)
@subsection(Loading the Routines)
	To include the interface as part of a SAIL program, the programmer
should use the statement,

	@index(REQUIRE Statement)@index(COMND.HDR File)REQUIRE "SAI:COMND.HDR" SOURCE!FILE;

@|somewhere within his declarations.  This will cause all the necessary declarations
to be made and will instruct the loader as to where to find the compiled
procedures.

@subsection(Naming Conventions)
	All of the procedures, arrays, variables, etc. in the COMND interface
package with which the SAIL programmer need concern himself have names beginning
with either @index(Cm! - Procedures)"cm!" or @index(Cm# - Procedures)"cm#".  Those beginning with "cm#" have to do specifically
with using multiple FDB's, whereas those beginning with "cm!" either have
nothing to do with multiple FDB's or are equally applicable to multiple and
single FDB's.

	The vast majority of the "cm!"-type procedures actually perform a call
to COMND.  These are named according to the particular call they perform.  Thus
the procedure cm!key performs the CMKEY function call, and the procedure cm!act
performs the CMACT function call.  The rest of the cm! procedures are used to
set up arrays, etc. needed by other procedures.  Thus cm!tbuild will construct
a table in the necessary format for cm!key and cm!swi from a string array of
keywords.

	In contrast, only one of the "cm#"-type procedures actually executes
a call to COMND. That procedure is called 
@index(Cm#Call Procedure)@indexentry(key="Cm# - Procedures Cm#Call",
entry="@ @ Cm#Call",Number)cm#call.  Most of the rest of the
cm# procedures set up their own particular FDB'S and link them into the chain.
Thus the cm#key procedure sets up and links in an FDB which when used will cause
the CMKEY function to be performed.  Once several FDB's have been set up, the
cm#call procedure is used to set things moving.

@Subsection(Handling Error and Reparse Conditions)
@Paragraph(Cm!Err and Cm!Reparse Flags)
	@index(Parsing Errors)When a field is unparsable (the user types in something that doesn't
make sense), the variable @index(Cm!Err Variable)
@indexentry(key="Variables Cm!Err",entry="@ @ Cm!Err",number)
cm!err will be set to the TOPS-20 error code indicating
the error.  Otherwise, cm!err will be zero upon return.  @index(Reparse)If a reparse is required,
the variable @index(Cm!Reparse Variable)
@indexentry(key="Variables Cm!Reparse",entry="@ @ Cm!Reparse",number)
cm!reparse will be set to true.  Otherwise it will be false.
Thus by testing these two variables after each call, the program can always
determine what it must do next -- go on and parse the next field,  reissue
all parse requests following the last cm!ini, or reissue all parse requests
including the cm!ini.  This will be shown in Part III.

@Paragraph(Cm!Retry - An Alternative Error Recovery Mechanism)
	@index(Cm!Retry Procedure)
@indexentry(key="Cm! - Procedures Cm!Retry",entry="@ @ Cm!Retry",number)
@indexentry(key="Parsing Errors And Cm!Retry",entry="@ @ And Cm!Retry",number)
In Part I it was explained that when a field is unparsable (cm!err
would be non-zero when using the interface), the program must start all over
right from the prompt.  This is not the only alternative, however, when using
the SAIL-COMND interface.  The procedure cm!retry takes one string parameter
and acts as follows:  First it prints its argument followed by a carriage
return - linefeed, then it retypes the entire command line up to but not including
the unparsable field.  The program should then reissue the call only for that
field.  It need not back up all the way to the beginning, and the user need
not retype all the things he typed correctly in the command line.  This was
not mentioned in Part I since it is not a feature of the COMND jsys.  It is
accomplished by playing with the CSB in such a way as to fool COMND into
thinking that everything has been redone as it should be.

@Paragraph(The Built-in Error Handler)
@index(Error Handler)	There is an error handler built into the interface which will trap
all errors occurring during execution of the COMND jsys and will act according
to the values of two variables which may be set by the program. 

	Errors are divided into two basic types: major errors and minor errors.
@Index(Major Errors)Major errors include all those errors which, if not trapped, would cause an
@Index(Illegal Instruction Interrupts)illegal instruction interrupt and stop the program dead.  This category includes
such things as command line overflow (the user types in more than can be held
in the command line buffer), an invalid CSB or FDB, etc.  @Index(Minor Errors)Minor errors are
all other errors which may occur.  This would include things such as failing
to confirm a command line with a carriage return when required,  typing a
word that does not match anything in a list of acceptable keywords, etc.

	The error handler handles minor and major errors in different ways.
@Indexentry(key="Error Handler And Minor Errors",entry="@ @ And Minor Errors",number)
If a minor error occurs, the error handler will look at the value of the
variable @index(Cm!Minor Variable)@Indexentry(key="Variables Cm!Minor",entry="@ @ Cm!Minor",number)
cm!minor.  If that value is true, then the TOPS-20 error message
corresponding to the error is printed.  If it is false, nothing is printed.
In either case, control is returned to the program with the appropriate TOPS-20
error code in the @index(Cm!Err Variable)@indexentry(key="Variables Cm!Err",entry="@ @ Cm!Err",number)cm!err variable.

@indexentry(key="Error Handler And Major Errors",entry="@ @ And Major Errors",number)
	If a major error occurs, the error handler inspects the value of the
variable @index(Cm!Major Variable)@Indexentry(key="Variables Cm!Major",entry="@ @ Cm!Major",number)
cm!major.  If that value is true, the appropriate TOPS-20 error
message is printed and the program halts.  Otherwise, nothing is printed, 
the TOPS-20 error code is placed in the variable @index(Cm!Err Variable)
@indexentry(key="Variables Cm!Err",entry="@ @ Cm!Err",number)
cm!err, and the variable
@index(Cm!Fatal Variable)@indexentry(key="Variables Cm!Fatal",entry="@ @ Cm!Fatal",number)
cm!fatal is set to true.  Then control is returned to the program.

	Until the program explicitly changes them, cm!minor and cm!major will
both be true.

@Subsection(The Atom Buffer)	Many of the procedures in the interface return values other than the
user's input as a string.  The cm!usr procedure, for instance, returns a TOPS-20
user number, rather than the user name as typed in by the person running the
program.  When using these procedures, however, it is often required to obtain
the input string itself.  In this case the 
@index(Cm!Getatm Procedure)@indexentry(key="Cm! - Procedures Cm!Getatm",entry="@ @ Cm!Getatm",number)
cm!getatm procedure is useful.

	When accepting input from the keyboard, COMND stores the user's input as
typed for each field in what is called the @index(Atom Buffer)"atom buffer" (thus the name cm!getatm).
Only one field's worth of input is stored in the atom buffer at a time.  Thus,
if a program makes a call to COMND to first get an output file name, then a
quoted string, the atom buffer will evolve as follows:
Before the initial CMINI call, the contents of the atom buffer will be unpredictable.  Between CMINI and the CMOFI call (the call to get an output file
specification), the atom buffer will be empty.  After the CMOFI call, the
atom buffer will contain the file specification as typed by the user, even 
though the cm!ofi procedure returns a SAIL channel number.  After the CMQST
call (the call to get a string delimited by double quotes), the atom buffer will
contain the string typed by the user, not including the quotes. 

	The cm!getatm procedure always returns the current contents of the
atom buffer in the form of a SAIL string.  Remember that the input for a
particular field is available only until the next COMND call (any call) is
made.

@subsection(Command Files)
	Often it is desirable for COMND to accept its input from somewhere
other than the keyboard.  This idea is most familiar to most users in the
form of the @index(LOGIN.CMD File)LOGIN.CMD and @index(COMAND.CMD File)COMAND.CMD files
that the EXEC@index(EXEC) can take commands from, and in terms of the EXEC's
TAKE@index(TAKE Command) command.  The cm!take procedure may be used @index(Cm!Take Procedure)@indexentry(key="Cm! - Procedures Cm!Take",entry="@ @ Cm!Take",number)
to achieve this effect.  After a call to cm!take, all following input to COMND
is gotten from the file specified, until the end of that file is reached.  At
that point, the file is closed, the 
@index(Cm!Eof Variable)@indexentry(key="Variables Cm!Eof",entry="@ @ Cm!Eof",number)
cm!eof variable is set to true, and the previous source of input is resumed.

@indexentry(key="Parsing Errors In Command Files",entry="@ @ In Command Files",number)
	There are two ways of handling errors that occur while input is coming
from a command file.
@begin(enumerate)
Automatically abort the file and resume taking input from the previous source.
In this case, the cm!abort @index(Cm!Abort Variable)@indexentry(key="Variables Cm!Abort",entry="@ @ Cm!Abort",number)
variable is set to true, and a message is printed saying that the file is
being aborted if the values of cm!minor and cm!major allow it.

Print error messages according to the values of cm!minor and cm!major and
continue to take commands from the command file.
@end(enumerate)

	Both of these options are available with the cm!take procedure.

@Subsection(Common Parameters)
	Many of the procedures in the interface have almost identical parameters.
Those that are common to a very large number of the procedures will be described 
now.  In the descriptions of the particular procedures these parameters will not
be rediscussed.

@begin(description)
@index(Help Parameter)@indexentry(key="Procedure Parameters Help",entry="@ @ Help",number)@index(Help Message)
help      a string which will be printed if the user types a @index(Question Mark)question
mark as his response.  The COMND jsys also has its own @index(Standard Help Message)@indexentry(key="Help Message Standard",entry="@ @ Standard",number)
standard
help messages, one for each different call.  These are
listed in the Monitor Calls Reference Manual.  The standard
help message will follow the supplied help message when both
are printed.  When using multiple FDB's, the help message for
@indexentry(key="Help Message And Multiple FDBs",entry="@ @ And Multiple FDBs",number)
each FDB will be printed on a new line, with the word "or"
separating help messages.  If this parameter is unspecified, it will default
to a null string.

@index(Def Parameter)@indexentry(key="Procedure Parameters Def",entry="@ @ Def",number)@index(Default String)
def       a string which will be used as the default response to this call.
If the user types an @index(Escape Character)escape character, and what he has typed so far matches
this string, then it will be filled in automatically for him.  If this
parameter is unspecified, it will default to a null string.
@indexentry(key="Default String And Multiple FDBs",entry="@ @ And Multiple FDBs",number)
When using multiple FDB's, only one default string may be specified, so
this parameter is included in the cm#call procedure, and left out of all
the other cm# procedures.

@index(Sup$Help Parameter)@indexentry(key="Procedure Parameters Sup$Help",entry="@ @ Sup$Help",number)@indexentry(key="Standard Help Message Suppressing",entry="@ @ Suppressing",number)
sup$help    a boolean value (true or false).  If this parameter is true, then
the standard help message will not be typed, whether or not the help parameter
is null.  If unspecified, sup$help defaults to false.

@index(Raise$Input Parameter)@indexentry(key="Procedure Parameters Raise$Input",entry="@ @ Raise$Input",number)@index(Upper Case Conversion)
raise$input    a boolean value.  If this parameter is true, then the user's input
will be converted to upper case before it is analyzed.  While this may not seem
to make any difference in many of the function calls, since they do not return
strings (e.g. cm!usr returns a TOPS-20 user number), it may be necessary for
a program to look in the atom buffer (via the cm!getatm procedure), in which
the conversion would be visible.  If the parameter is not specified it defaults
to a value of false.

@index(No$Indirect Parameter)@indexentry(key="Procedure Parameters No$Indirect",entry="@ @ No$Indirect",number)@index(Indirect Files)
no$indirect    a boolean value.  If this parameter is false, then the user will
be able to respond to this field with something of the form "@@filename", causing
the contents of the file whose name is filename to be used to complete the field.
If no$indirect is true, this will not be allowed, and a minor error will result
if such an attempt is made.  If the parameter is not specified it will default
to a value of false.

@index(Wake$Always Parameter)@indexentry(key=Procedure Parameters Wake$Always",entry="@ @ Wake$Always",number)@indexentry(key="Action Characters Extending",entry="@ @ Extending",number)
wake$always    It was mentioned in Part I that when COMND is accepting input
from the terminal, it won't start looking at it until an action character is
typed.  This is not always true, however.  If the wake$always parameter is
true, then COMND will wake up whenever it senses that the field has been
completed.  Thus it will wake up on such characters a spaces, commas, etc.
One use for this comes when it is required to obtain a @index(Obtaining Passwords)password from a user.
The command line would be parsed with wake$always true on every call, and then
as soon as the field before the password has been completed, the program would
@index(Turning Off Echoing)turn off terminal echoing so that the password would not show up on the terminal
as it was typed.  If wake$always were false in this case, COMND may not even 
begin parsing the password field until after it has been typed in, and then
it would probably be too late to turn off echoing.  If wake$always is not
specified it will default to a value of false.

@index(Brchars Parameter)@indexentry(key="Procedure Parameters Brchars",entry="@ @ Brchars",number)@index(Break Characters)
Brchars   This is a string of characters on which the current field is to
be broken.  That is, if any of these characters is encountered while parsing
this field, the field will be considered terminated.  These characters do not
become action characters.  If the string is null, the standard break table
@index(Standard Break Characters)@indexentry(key="Break Characters Standard",entry="@ @ Standard",number)
will be used for the field.  Different field types (i.e. COMND functions)
have different standard break tables, and only a few of them use break
tables at all.  Of those few, only about half have user-changeable break
tables.  The standard break tables will be described along with the descriptions
of the cm!-type procedures for the corresponding COMND functions.  There is also 
a convenient table showing the standard break tables for all COMND functions
that use them in Appendix 1.
@end(description)
@Section(Specifics)
	This section looks at all the cm! - type procedures in the interface
in detail.  The discussions appear in alphabetical order, and each description
is introduced by a reproduction of the procedure definition header.
Note that
those parameters which were discussed in the preceding section will be included
in the procedure headers, but otherwise will not be mentioned in the descriptions
in this section.

@subsection(The Cm!Act Procedure)
@index(Cm!Act Procedure)@indexentry(key="Cm! - Procedures Cm!Act",entry="@ @ Cm!Act",number)@index(Account Name Fields)
@verbatim{
string procedure cm!act
	(string help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
	The cm!act procedure performs the 
@indexentry(key="COMND Functions CMACT",entry="@ @ CMACT",number)
CMACT (ACT = ACcounT) function call of the COMND
jsys.  It is used to parse an account name string.  The string, up to but
not including the first non-alphanumeric character typed is returned as the
value of the function.  No verification of the account name is done, so
a minor error cannot occur in this procedure.  
@indexentry(key="Standard Help Message CMACT",entry="@ @ CMACT",number)There is no standard help
message for the CMACT call, so if the help parameter is null, no help
message will be printed when the user types a question mark.

@subsection(The Cm!Cfm Procedure)
@index(Cm!Cfm Procedure)@indexentry(key="Cm! - Procedures Cm!Cfm",entry="@ @ Cm!Cfm",number)@index(Confirmation Fields)
@verbatim{
procedure cm!cfm
	(string help(null);
	 boolean sup$help(false));
}
	The cm!cfm procedure performs the 
@indexentry(key="COMND Functions CMCFM",entry="@ @ CMCFM",number)
CMCFM (CFM = ConFirM) function call of the COMND
jsys.  The only valid user input for this call is a carriage return.
@index(Terminating Command Lines)@indexentry(key="Command Line ATerminating",entry="@ @ Terminating",number)
It is generally good practice to make this the last call of every command
line.  This gives the user a chance to correct mistakes in the command line
before any action is taken. 
@indexentry(key="Standard Help Message CMCFM",entry="@ @ CMCFM",number)
The standard help message for the 
CMCFM function call is "CONFIRM WITH CARRIAGE RETURN".  Note that several
of the common parameters are not included in this procedure, simply because
they do not make sense here.

@subsection(The Cm!Cma Procedure)
@index(Cm!Cma Procedure)@indexentry(key="Cm! - Procedures Cm!Cma",entry="@ @ Cm!Cma",number)@index(Comma Fields)
@verbatim{
procedure cm!cma
	(string help(null);
	 boolean sup$help(false));
}
	The cm!cma procedure performs the 
@indexentry(key="COMND Functions CMCMA",entry="@ @ CMCMA",number)
CMCMA (CMA = CoMmA) function call of the COMND
jsys.  The only valid user input for this call is a comma. 
This procedure would be used, for instance, when a list of input  file names
is needed.  The program would keep calling first the cm!ifi procedure (see
below), then the cm!cma procedure until cm!cma fails, at which point the user
did not type a comma, so the program should try other possibilities, such as
cm!cfm (above). 
@indexentry(key="Standard Help Message CMCMA",entry="@ @ CMCMA",number)
The standard
help message for the CMCMA function call is "COMMA".  Note that, as with
the cm!cfm procedure, several of the common parameters are not included in
this procedure, because they do not make sense here.

@subsection(The Cm!Dev Procedure)
@index(Cm!Dev Procedure)@indexentry(key="Cm! - Procedures Cm!Dev",entry="@ @ Cm!Dev",number)@index(Device Name Fields)
@verbatim{
integer procedure cm!dev
	(string help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false);
	 string brchars(null));
}
	The cm!dev procedure performs the 
@indexentry(key="COMND Functions CMDEV",entry="@ @ CMDEV",number)
CMDEV (DEV = DEVice) function call of the COMND
jsys.  It is used for parsing a device name.  This could be a physical
device name or a logical name.  The procedure returns the device designator
corresponding to the device name input.  
@indexentry(key="Standard Help Message CMDEV",entry="@ @ CMDEV",number)
The standard help message for the
CMDEV call is "DEVICE NAME".

@indexentry(key="Standard Break Characters CMDEV",entry="@ @ CMDEV",number)
	The standard break table for CMDEV is as follows:

@verbatim{
		ASCII Codes    Description
		   0 - 37      All Control Characters
		  40 - 54      Space Through Comma
		  56 - 57      Dot and Slash
		  72 - 76      Colon Through Pound Sign (#)
		 100	       Atsign (@@)
		 133 - 136     Open Bracket Through Up-Arrow
		 140	       Apostrophe
		 173 - 177     Close Bracket Through Tilde
}
@Subsection(The Cm!Dir Procedure)
@index(Cm!Dir Procedure)@indexentry(key="Cm! - Procedures Cm!Dir",entry="@ @ Cm!Dir",number)@index(Directory Name Fields)
@verbatim{
integer procedure cm!dir
	(string help(null),def(null);
	 boolean sup$help(false),
		 allow$wild(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false),
		 parse$only(false));
}
	The cm!dir procedure performs the 
@indexentry(key="COMND Functions CMDIR",entry="@ @ CMDIR",number)
CMDIR (DIR = DIRectory) function call of the COMND
jsys.  It is used for parsing a directory name (with angle brackets - <>).
The procedure returns the 36-bit directory number corresponding to the
directory named by the user's input.  If the 
@index(Allow$Wild Parameter)@indexentry(key="Procedure Parameters Allow$Wild",entry="@ @ Allow$Wild",number)
allow$wild parameter is true,
@index(Wildcard Characters)wildcard characters ("*" and "%") will be allowed as part of the directory
name.  Otherwise they will cause a minor error.  If 
@index(Parse$Only Parameter)@indexentry(key="Procedure Parameters Parse$Only",entry="@ @ Parse$Only",number)
parse$only is true,
then the field will be parsed, but if the input does not match an existing
directory no minor error will occur.  The directory number can be translated
into a directory name string using SAIL's @index(DIRST Built-in SAIL Function)DIRST built-in function.  The
@indexentry(key="Standard Help Message CMDIR",entry="@ @ CMDIR",number)
standard help message for the CMDIR function call is "DIRECTORY NAME".

@Subsection(The Cm!Fil Procedure)
@index(Cm!Fil Procedure)@indexentry(key="Cm! - Procedures Cm!Fil",entry="@ @ Cm!Fil",number)@index(File Name Fields)
@Verbatim{
integer procedure cm!fil
	(string help(null),def(null);
	 integer flag$gen('440004000000);
	 string device(null),
		directory(null),
		name(null),
		extension(null),
		protection(null),
		account(null);
	 integer jfn(0);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
The cm!fil procedure performs the CMFIL
@indexentry(key="COMND Functions CMFIL",entry="@ @ CMFIL",number)
(FIL = FILe) function call of the COMND jsys.  It is used to parse
an arbitrary file specification (i.e. where neither cm!ifi nor cm!ofi is
quite right).  This call uses the @index(GTJFN Jsys)GTJFN jsys to process the file specification,
and so there many new parameters for this procedure which are used to fill
in the GTJFN Argument Block@index(GTJFN Argument Block).  To find the details
of the contents of this block, see the Monitor Calls Reference Manual.  The
new parameters are as follows:

@begin(description)
flag$gen   @index(Flag$Gen Parameter)@indexentry(key="Procedure Parameters Flag$Gen",entry="@ @ Flag$Gen",number)
The integer passed for this parmeter will be placed into word  0 (.GJGEN) 
of the GTJFN argument block.
@indexentry(key="GTJFN Argument Block Word 0 (.GJGEN)",entry="@ @ Word 0 (.GJGEN)",number)
It contains various flags in the left half, and a default generation number
in the right half.  See the Monitor Calls Reference Manual for details on
the contents of this word.  If the flag$gen parameter is not specified, it
will default to octal 440004000000, and cm!fil will behave like cm!ofi.

device   @index(Device Parameter)@indexentry(key="Procedure Parameters Device",entry="@ @ Device",number)
A pointer to the string supplied for this parameter will be placed
in word 2 (.GJDEV) of the GTJFN Argument Block@indexentry(key="GTJFN Argument Block Word 2 (.GJDEV)",entry="@ @ Word 2 (.GJDEV)",number).
The string will become the default for the device field of thef file specification.
If no string is specified, the default device will be the currently connected structure.

directory   
@index(Directory Parameter)@indexentry(key="Procedure Parameters Directory",entry="@ @ Directory",number)
A pointer to the string supplied for this parameter will be placed in word 3
(.GJDIR) of the GTJFN Argument Block.@indexentry(key="GTJFN Argument Block Word 3 (.GJDIR)",entry="@ @ Word 3 (.GJDIR)",number)
The string will become the default for the directory field of the file specification.
If no string is passed, the default directory will be the currently connected directory.

name   @index(Name Parameter)@indexentry(key="Procedure Parameters Name",entry="@ @ Name",number)
A pointer to the string supplied for this parameter will be placed in word 4
(.GJNAM) of the GTJFN Argument Block.@indexentry(key="GTJFN Argument Block Word 4 (.GJNAM)",entry="@ @ Word 4 (.GJNAM)",number)
The string will become the default for the name field of the file specification.
If no string is passed, there will be no default name field.

extension   @index(Extension Parameter)@indexentry(key="Procedure Parameters Extension",entry="@ @ Extension",number)
A pointer to the string supplied for this parameter will be placed in word 5
(.GJEXT) of the GTJFN Argument Block.@indexentry(key="GTJFN Argument Block Word 5 (.GJEXT)",entry="@ @ Word 5 (.GJEXT)",number)
The string will become the default for the extension field of the file specification.
If no string is passed the default extension will be null.

protection   @index(Protection Parameter)@indexentry(key="Procedure Parameters Protection",entry="@ @ Protection",number)
A pointer to the string supplied for this parameter will be stored in word 6
(.GJPRO) of the GTJFN Argument Block.@indexentry(key="GTJFN Argument Block Word 6 (.GJPRO)",entry="@ @ Word 6 (.GJPRO)",number)
The string will become the default for the protection field of the file specification.
If no string is passed the default protection will be whatever is specified
in the directory, or the protection of the next lower generation.

account   @index(Account Parameter)@indexentry(key="Procedure Parameters Account",entry="@ @ Account",number)
A pointer to the string passed for this parameter will be placed in word 7
(.GJACT) of the GTJFN Argument Block.@indexentry(key="GTJFN Argument Block Word 7 (.GJACT)",entry="@ @ Word 7 (.GJACT)",number)
The string will become the default account for the file specification.
If no string is specified the default account will be the LOGIN account set
for the user.

jfn   @index(Jfn Parameter)@indexentry(key="Procedure Parameters Jfn",entry="@ @ Jfn",number)
The integer passed for this parameter will be placed in word 10 (.GJJFN) of the
GTJFN Argument Block.@indexentry(key="GTJFN Argument Block Word A10 (.GJJFN)",entry="@ @ Word 10 (.GJJFN)",number)
The system will attempt to assign this number as the jfn for the file specification
obtained in the call.  If you specify this parameter, make sure you set bits
9 and 10 (GJ%JFN) 
@indexentry(key="GTJFN Argument Block Word 0 (.GJGEN) GJ%JFN Bits",entry="@ @ @ @ GJ%JFN Bits",number)
in flag$gen appropriately.  See the Monitor Calls Reference
Manual to find out the possible bit patterns.  If this parameter is not specified
it will be given the value zero.
@end(description)

Note that any fields present in the def parameter will take precedence over
any defaults passed in the parameters listed above.

	The cm!fil procedure will return a SAIL channel number for the file
that is obtained.  The channel will not be open.  Use the OPENF built-in
SAIL function to open the file.  @indexentry(key="Standard Help Message CMFIL",entry="@ @ CMFIL",number)
The standard help message for CMFIL is "OUTPUT FILESPEC" if bits 0 and 2
(GJ%FOU and GJ%OLD)
@indexentry(key="GTJFN Argument Block Word 0 (.GJGEN) GJ%FOU Bit",entry="@ @ @ @ GJ%FOU Bit",number)
@indexentry(key="GTJFN Argument Block Word 0 (.GJGEN) GJ%OLD Bit",entry="@ @ @ @ GJ%OLD Bit",number)
are both on in flag$gen.  Otherwise it is "INPUT FILESPEC".

@Subsection(The Cm!Fld Procedure)
@index(Cm!Fld Procedure)@indexentry(key="Cm! - Procedures Cm!Fld",entry="@ @ Cm!Fld",number)@index(Arbitrary Fields)
@verbatim{
string procedure cm!fld
	(string help(null),def(null);
	 boolean raise$input(false),
		 no$indirect(false),
		 wake$always(false);
	 string brchars(null));
}
	The cm!fld procedure performs the 
@indexentry(key="COMND Functions CMFLD",entry="@ @ CMFLD",number)
CMFLD (FLD = FieLD) function call of the COMND
jsys.  This procedure is used when none of the other procedures seem to fit
the required application. The user's input, as delimited by the first 
non-alphanumeric character, is returned as the value of the function.  The
delimiting character is not part of the string returned.  
@indexentry(key="Standard Help Message CMFLD",entry="@ @ CMFLD",number)
There is no standard
help message for the CMFLD function call.
@indexentry(key="Standard Break Characters CMFLD",entry="@ @ CMFLD",number)

	The standard break table for CMFLD is as follows:
@verbatim{
	ASCII Codes	Description
	   0 - 37	All Control Characters
	  40 - 54	Space Through Comma
	  56 - 57	Dot and Slash
	  72 - 77	Colon Through Question Mark
	 100		Atsign (@@)
	 133 - 140	Open Bracket Through Accent Grave
	 173 - 177	Close Bracket Through Tilde
}

@Subsection(The Cm!Flt Procedure)
@index(Cm!Flt Procedure)@indexentry(key="Cm! - Procedures Cm!Flt",entry="@ @ Cm!Flt",number)@index(Real Number Fields)@index(Numeric Fields)
@verbatim{
real procedure cm!flt
	(string help(null),def(null);
	 boolean sup$help(false),
		 no$indirect(false),
		 wake$always(false));
}
	The cm!flt procedure performs the 
@indexentry(key="COMND Functions CMFLT",entry="@ @ CMFLT",number)
CMFLT (FLT = FLoaT) function call of
the COMND jsys.  This procedure is used to parse a real number.  The number
is returned as the value of the function.  There is no raise$input parameter,
since alphabetic characters are invalid for this field anyway.  
@indexentry(key="Standard Help Message CMFLT",entry="@ @ CMFLT",number)
The standard
help message for the CMFLT function call is "NUMBER".

@Subsection(The Cm!Getatm Procedure)
@index(Cm!Getatm Procedure)@indexentry(key="Cm! - Procedures Cm!Getatm",entry="@ @ Cm!Getatm",number)@index(Atom Buffer)
@verbatim{
string procedure cm!getatm;
}
	The cm!getatm returns the current contents of the atom buffer (see
discussion in Part II, Section 1 above).  The procedure does not call the
COMND jsys or alter the state of any related storage areas (in particular
the atom buffer is unchanged).

@Subsection(The Cm!Ifi Procedure)
@index(Cm!Ifi Procedure)@indexentry(key="Cm! - Procedures Cm!Ifi",entry="@ @ Cm!Ifi",number)@index(File Name Fields)@index(Input File Fields)
@verbatim{
integer procedure cm!ifi
	(string help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
	The cm!ifi procedure performs the 
@indexentry(key="COMND Functions CMIFI",entry="@ @ CMIFI",number)
CMIFI (IFI = Input FIle) function
call of the COMND jsys.  It is used for parsing the name of a file to be
used for input (i.e., the file must exist).  The procedure returns a
SAIL channel number as its value (so the calling program need not use SAIL's
SETCHAN built-in function).  The file is not opened by cm!ifi.
To open the file for reading, the calling program
would use SAIL's OPENF built-in procedure using the channel number returned
by cm!ifi.  
@indexentry(key="Standard Help Message CMIFI",entry="@ @ CMIFI",number)
The standard help string for the CMIFI function call is "INPUT
FILESPEC".

@Subsection(The Cm!Ini Procedure)@label(cm!iniproc)
@index(Cm!Ini Procedure)@indexentry(key="Cm! - Procedures Cm!Ini",entry="@ @ Cm!Ini",number)@index(Initializing The CSB)
@verbatim{
boolean procedure cm!ini
	(string prompt;
	 boolean newcomm(true));
}
	The cm!ini procedure performs the 
@indexentry(key="COMND Functions CMINI",entry="@ @ CMINI",number)
CMINI (INI = INItialize) function
of the COMND jsys.  It is always the first call that should be made when
starting to parse a new command line.  When called it will initialize the
CSB and the various buffers used to hold the user's input, and will issue
the @index(Command Line Prompt)command line prompt.  
@index(Prompt Parameter)@indexentry(key="Procedure Parameters Prompt",entry="@ @ Prompt",number)
This prompt is supplied via the prompt parameter
to the procedure.  The end of this prompt marks the farthest back that the
user will be allowed to delete when using COMND. The cm!ini procedure causes
no input to be read from the keyboard, unlike all the rest of the COMND function
calls.  
@indexentry(key="Standard Help Message CMINI",entry="@ @ CMINI",number)
And of course, there is no standard help message.

	The newcomm parameter @index(Newcomm Parameter)
@indexentry(key="Procedure Parameters Newcomm",entry="@ @ Newcomm",number)
determines whether or not the ctrl/h feature will be available in this
command line (see section @ref(ctrl/hfea), page @pageref(ctrl/hfea)).
If this call to cm!ini is being made because a parsing error was just encountered
in a command line, then it would probably be desirable to activate the ctrl/h
feature.  In this case, specify a value of false for the newcomm parameter.

	If this is the beginning of a new command line, or if for some other
reason the ctrl/h feature should not be activated, specify a value of true
for the newcomm parameter.

	If the ctrl/h feature is activated and the user actually does use
the feature to retype a portion of the command line, then the cm!ini will
return a value of false.  Otherwise it will return a value of true.  Note
that this value, like any value returned by a SAIL procedure, may be ignored,
and the newcomm parameter is an optional parameter defaulting to true, so
the ctrl/h feature is upward compatible with previous versions of the interface
which did not provide for the feature.

	An example using the ctrl/h feature is included in Part III.

@Subsection(The Cm!Key Procedure)
@index(Cm!Key Procedure)@indexentry(key="Cm! - Procedures Cm!Key",entry="@ @ Cm!Key",number)@index(Keyword Fields)
@Verbatim{
integer procedure cm!key
	(integer array table;
	 string help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false);
	 string brchars(null));
}
	The cm!key procedure performs the 
@indexentry(key="COMND Functions CMKEY",entry="@ @ CMKEY",number)
CMKEY (KEY = KEYword) function call
of the COMND jsys.  It is used when the user must type one out of a list of
possible keywords.  The keywords are originally stored in a string array,
one keyword per array element.  The array is then submitted to the cm!tbuild
procedure (below) which converts it into a @index(TBLUK Lookup Table)TBLUK lookup table (see the description of 
the @index(TBLUK Jsys)TBLUK jsys in the Monitor Calls Reference Manual for details on the format
of this table), which is stored in an integer array.  This array is then supplied
to cm!key as the @index(Table Parameter)@indexentry(key="Procedure Parameters Table",entry="@ @ Table",number)
table parameter.  If the user's input matches one of the
valid keywords, then the index of that keyword in the original string array
is returned as the value of the function.  Otherwise a minor error will occur,
and a zero will be returned.

@index(Wizard Note)@Quotation(Note to wizards:  If you are planning to build your own TBLUK lookup
tables, take note!  The right half of the table entry for each keyword
should contain the integer that you want returned by COMND if that keyword
is selected.  The cm!tbuild procedure stores the original string array
indices in these half-words.)

@indexentry(key="Standard Help Message CMKEY",entry="@ @ CMKEY",number)
	The standard help message for the CMKEY function call is
"ONE OF THE FOLLOWING", followed by an alphabetical list of all the
keywords which could still possibly match what the user has typed in
so far.  If there are no possible matches,  the message "KEYWORD (NO
DEFINED KEYWORDS MATCH THIS INPUT)" is typed.

	The standard break table for CMKEY is:
@indexentry(key="Standard Break Characters CMKEY",entry="@ @ CMKEY",number)
@verbatim{
	ASCII Codes	Description
	   0 - 37	All Control Characters
	  40 - 54	Space Through Comma
	  56 - 57	Dot and Slash
	  72 - 77	Colon Through Question Mark
	 100		Atsign (@@)
	 133 - 140	Open Bracket Through Accent Grave
	 173 - 177	Close Bracket Through Tilde
}
@Subsection(The Cm!Nod Procedure)
@index(Cm!Nod Procedure)@indexentry(key="Cm! - Procedures Cm!Nod",entry="@ @ Cm!Nod",number)@index(Node Name Fields)
@Verbatim{
string procedure cm!nod
	(string help(null),def(null);
	 boolean sup$help(false),
	 	 no$indirect(false),
		 wake$always(false));
}
The cm!nod procedure performs the CMNOD (NOD = NODe)
@indexentry(key="COMND Functions CMNOD",entry="@ @ CMNOD",number)
function call of the COMND jsys.  This procedure is used to parse a
network node name, which consists of from 1 to 6 characters followed
by two colons.  The node name (without the colons) is returned as the value of the procedure.
Lowercase characters are always converted to upper case (hence no
raise$input parameter).  Note that a successful return does not guarantee
the existence of the node - only that the field was typed in the correct
syntax.  @indexentry(key="Standard Help Message CMNOD",entry="@ @ CMNOD",number)
The standard help message for CMNOD is "NODE NAME".

@subsection(The Cm!Noi Procedure)
@index(Cm!Noi Procedure)@indexentry(key="Cm! - Procedures Cm!Noi",entry="@ @ Cm!Noi",number)@index(Noise Words)@index(Guide Words)
@Verbatim{
procedure cm!noi
	(string noise);
}
	The cm!noi procedure performs the 
@indexentry(key="COMND Functions CMNOI",entry="@ @ CMNOI",number)
CMNOI (NOI = NOIse word) function
call of the COMND jsys.  It is used to display a string which will guide
the user by telling him what should be input for the next field, or by qualifying
what he typed in the last field.  If the user terminates a field with an @index(Escape Character)ESCAPE
character, and the next procedure executed is cm!noi, then the 
@index(Noise Parameter)@indexentry(key="Procedure Parameters Noise",entry="@ @ Noise",number)
noise string
supplied as a parameter will be output surrounded by parentheses (the parentheses
should not be included as part of the parameter passed to cm!noi).  If he
terminates the field with a non-action character, then he has the option of
either typing the guide word himself, or ignoring it altogether.  It will not
be typed for him.  The only minor error that can occur here will result if the
user attempts to type in the noise word by himself, but gets it wrong.
@indexentry(key="Standard Help Message CMNOI",entry="@ @ CMNOI",number)
There is no standard help message (or nonstandard, for that matter) for the
CMNOI function call.

@Subsection(The Cm!Num Procedure)
@index(Cm!Num Procedure)@indexentry(key="Cm! - Procedures Cm!Num",entry="@ @ Cm!Num",number)@index(Integer Fields)@index(Numeric Fields)
@Verbatim{
integer procedure cm!num
	(string help(null),def(null);
	 boolean sup$help(false);
	 integer radix(10);
	 boolean no$indirect(false),
		 wake$always(false));
}
	The cm!num procedure performs the 
@indexentry(key="COMND Functions CMNUM",entry="@ @ CMNUM",number) 
CMNUM (NUM = NUMber) function call
of the COMND jsys.  It is used for parsing an integer number.  The 
@index(Radix Parameter)@indexentry(key="Procedure Parameters Radix",entry="@ @ Radix",number)
radix
parameter specifies in what @index(Number Bases)base the number is to be interpreted, and must
be between 2 and 10 inclusive.  The number typed is returned as the value
of the procedure.  There is no raise$input parameter, since, as in cm!flt,
no alphabetic characters are valid anyway.  
@indexentry(key="Standard Help Message CMNUM",entry="@ @ CMNUM",number)
The standard help message is 
"DECIMAL NUMBER" if radix is 10, "OCTAL NUMBER" if radix is 8, and "A NUMBER
IN BASE nn" if radix (nn) is anything else.  The radix parameter defaults to
10 if it is left unspecified.

@Subsection(The Cm!Nux Procedure)
@index(Cm!Nux Procedure)@indexentry(key="Cm! - Procedures Cm!Nux",entry="@ @ Cm!Nux",number)@index(Numeric Fields)@index(Integer Fields)
@Verbatim{
integer procedure cm!nux
	(string help(null),def(null);
	 boolean sup$help(false);
	 integer radix(10);
	 boolean no$indirect(false),
		 wake$always(false));
}
The cm!nux procedure performs the CMNUX (NUX = NUmber, sort of)
@indexentry(key="COMND Functions CMNUX",entry="@ @ CMNUX",number)
function call of the COMND jsys.  This procedure is used to parse
an integer number field, as in cm!num, the only difference being that
cm!nux will terminate on the first non-numeric character, without giving
a minor error, even if that character is not one of the valid terminators
for cm!num.  The number is returned as the value of the procedure.
The radix parameter is as in cm!num.@index(Radix Parameter)
@indexentry(key="Procedure Parameters Radix",entry="@ @ Radix",number)
@indexentry(key="Standard Help Message CMNUX",entry="@ @ CMNUX",number)
The standard help message for CMNUX is the same as for CMNUM.

@Subsection(The Cm!Ofi Procedure)
@index(Cm!Ofi Procedure)@indexentry(key="Cm! - Procedures Cm!Ofi",entry="@ @ Cm!Ofi",number)@index(File Name Fields)@index(Output File Fields)
@Verbatim{
integer procedure cm!ofi
	(string help(null),def(null);
	 boolean sup$help(false),
		 rase$input(false),
		 no$indirect(false),
		 wake$always(false));
}
	The cm!ofi procedure performs the 
@indexentry(key="COMND Functions CMOFI",entry="@ @ CMOFI",number)
CMOFI (OFI = Output FIle) function
call of the COMND jsys.  It is almost identical to cm!ifi (above), but the
user's input is this time expected to specify an output file.  Thus, it is
not necessary that the file exist already, and if it does exist, then the
default generation number will be one higher than the highest existing generation
number for the file.  Like cm!ifi, cm!ofi returns a SAIL channel number, not
just a JFN.  To open the file for output, use SAIL's OPENF built-in procedure.
The standard help message for the 
@indexentry(key="Standard Help Message CMOFI",entry="@ @ CMOFI",number)
CMOFI function call is "OUTPUT FILESPEC".

@Subsection(The Cm!Qst Procedure)
@index(Cm!Qst Procedure)@indexentry(key="Cm! - Procedures Cm!Qst",entry="@ @ Cm!Qst",number)@index(Quoted String Fields)
@Verbatim{
string procedure cm!qst
	(string help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
The cm!qst procedure performs the CMQST (QST = Quoted STring) function
@indexentry(key="COMND Functions CMQST",entry="@ @ CMQST",number)
call of the COMND jsys.  It is used to parse a string of text surrounded
by double quotes.  The string is returned without the quotes.  This function
is useful for obtaining strings which may include action characters,@index(Action Characters)
since these characters lose their significance after the opening quote in cm!qst.
If a quote is desired in the string, the user must type two consecutive
quotes.    A carriage return@index(Carriage Return) is an illegal character
inside the string.  
@indexentry(key="Standard Help Message CMQST",entry="@ @ CMQST",number)
The standard help message for CMQST is "QUOTED STRING".

@Subsection(The Cm!Retry Procedure)
@index(Cm!Retry Procedure)@indexentry(key="Cm! - Procedures Cm!Retry",entry="@ @ Cm!Retry",number)
@verbatim{
procedure cm!retry
	(string errmsg);
}
@indexentry(key="Parsing Errors And Cm!Retry",entry="@ @ And Cm!Retry",number) 
	The cm!retry may be used as an alternative to reparsing the entire
command line when an invalid response is given by the user to a field.  Instead,
upon detecting a non-zero cm!err, the program calls cm!retry with an appropriate
@index(Errmsg Parameter)@indexentry(key="Procedure Parameters Errmsg",entry="@ @ Errmsg",number)
error message as a parameter, and then it reissues the COMND call just for the
field in which the error occurred.  When cm!retry is called, it first prints
its argument, then it patches up the CSB to make COMND think everything up
to that field has already been reparsed.  This procedure should be used with
@indexentry(key="Cm!Retry Procedure Caution",entry="@ @ Caution",number)
caution, since it plays with the CSB in such a way that, if the COMND jsys internals
were changed in a later monitor release, cm!retry could fall flat on its face.

@Subsection(The Cm!Size Procedure)
@index(Cm!Size Procedure)@indexentry(key="Cm! - Procedures Cm!Size",entry="@ @ Cm!Size",number)@indexentry(key="TBLUK Lookup Table Computing Size With Cm!Size",entry="@ @ Computing Size With Cm!Size",number)
@Verbatim{
integer procedure cm!size
	(string array strarr);
}
	This procedure computes and returns the number of storage words
necessary to build a TBLUK lookup table containing the strings in strarr
@indexentry(key="Procedure Parameters Strarr",entry="@ @ Strarr",number)@index(Strarr Parameter)
(see cm!tbuild below).  This number could be used as a dimensioning bound
on an integer array which will be used to hold the table.  The lower bound
on the integer array should be zero.

@Subsection(The Cm!Swi Procedure)
@index(Cm!Swi Procedure)@indexentry(key="Cm! - Procedures Cm!Swi",entry="@ @ Cm!Swi",number)@index(Switch Fields)
@Verbatim{
integer procedure cm!swi
	(integer array table;
	 string help(null),def(null);
	 bollean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false);
	 string brchars(null);
}
	The cm!swi procedure performs the 
@indexentry(key="COMND Functions CMSWI",entry="@ @ CMSWI",number)
CMSWI (SWI = SWItch) function call
of the COMND jsys.  It operates almost identically with the cm!key procedure.
The main difference is that a @index(Switches)@index(Slash)switch should start with a slash ("/") when
typed in by the user.  A minor error occurs here if that is not the case.
Slashes should not, however, be included in the strings making up the TBLUK
lookup table.  Their presence is assumed.
	As in the cm!key procedure, the 
@index(Table Parameter)@indexentry(key="Procedure Parameters Table",entry="@ @ Table",number)
table parameter may be prepared by
using the cm!tbuild procedure (below).  Wizards should read the "Note to
Wizards" in the description of the cm!key procedure above.
	Often a switch will be terminated by a @index(Colon)colon, usually indicating that
some value is to follow.  When this occurs, the variable 
@index(Cm!Colon Variable)@indexentry(key="Variables Cm!Colon",entry="@ @ Cm!Colon",number)
cm!colon will be set
to true by the cm!swi procedure.  Colons may be included in the strings making
up the TBLUK lookup table, in which case they will be included whenever the
user uses recognition to finish typing the switch name.
@indexentry(key="Standard Help Message CMSWI",entry="@ @ CMSWI",number)
	The standard help message is "ONE OF THE FOLLOWING", followed by
an alphabetical list of those switches which still may be matched by what
has been typed so far. If no switch can possibly be matched, the message
"KEYWORD (NO DEFINED KEYWORDS MATCH THIS INPUT)" is typed.

@indexentry(key="Standard Break Characters CMSWI",entry="@ @ CMSWI",number)
	The standard break table for CMSWI is as follows:
@verbatim{
	ASCII Codes	Description
	   0 - 37	All Control Characters
	  40 - 54	Space Through Comma
	  56 - 57	Dot and Slash
	  72 - 77	Colon Through Question Mark
	 100		Atsign (@@)
	 133 - 140	Open Bracket Through Accent Grave
	 173 - 177	Close Bracket Through Tilde
}

@Subsection(The Cm!Tad Procedure)
@index(Cm!Tad Procedure)@indexentry(key="Cm! - Procedures Cm!Tad",entry="@ @ Cm!Tad",number)@index(Time Fields)@index(Date Fields)@index(Time And Date Fields)
@Verbatim{
integer procedure cm!tad
	(string help(null),def(null);
	 boolean sup$help(false),
		 date(true),time(true),
		 no$convert(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
The cm!tad procedure performs the CMTAD (TAD = Time And Date) 
@indexentry(key="COMND Functions CMTAD",entry="@ @ CMTAD",number)
function call of the COMND jsys.  This procedure is used to parse a time
and/or a date.  If the date parameter @index(Date Parameter)@indexentry(key="Procedure Parameters Date",entry="@ @ Date",number)
is true, a date will be parsed.  If time is true@index(Time Parameter)@indexentry(key="Procedure Parameters Time",entry="@ @ Time",number)
a time will be parsed.  Both default to true.  If no$convert is false (the
default) @index(No$Convert Parameter)@indexentry(key="Procedure Parameters No$Convert",entry="@ @ No$Convert",number)
then the date/time is returned in internal format @index(Internal Date/Time Format) (see the Monitor Calls Reference Manual).  Otherwise a zero is returned,
and the date and time information are stored in integer array
@index(Cm!Datime Array)@indexentry(key="Variables Cm!Datime (Array)",entry="@ @ Cm!Datime (Array)",number)
cm!datime (dimensioned [2:4] so as to agree with accumulator assignments in the IDTNC monitor
call return@index(IDTNC jsys)) as follows:
@verbatim{
	Element	       Contents
	cm!datime[2]   Year in Left Half
		       Month (0=Jan) in Right Half
	cm!datime[3]   Day of Month (0=1st Day) in Left Half
		       Day of Week (0=Mon) in Right Half
	cm!datime[4]   Flag Bits in Left Half
		       Seconds Since Midnight in Right Half
}
The flag bits returned in the left half of cm!datime[4] are as follows:
@verbatim{
	Bit Number	Meaning (if bit is on)
	   0		A Time Zone was input
	   1		Daylight Savings Time was input
	   2		A Time Zone was input
	   3		A Julian Day Format was input
	 12-17		Time Zone, if one was specified, or
			the Local Time Zone
}
@indexentry(key="Standard Help Message CMTAD",entry="@ @ CMTAD",number)
The standard help message for CMTAD is "DATE" if date was true, "TIME"
if time was true, and "DATE AND TIME" if both were true.

@subsection(The Cm!Take Procedure)
@index(Cm!Take Procedure)@indexentry(key="Cm! - Procedures Cm!Take",entry="@ @ Cm!Take",number)@index(Command Files)
@verbatim{
procedure cm!take
	(integer ichan, ochan(nulio);
	 boolean errpop(true));
}
The cm!take procedure facilitates the redirection of input and output
during operation of COMND to other files.  It gets its name from its
functional similarity to the EXEC's TAKE command@index(EXEC)@index(TAKE Command).
The ichan parameter @index(Ichan Parameter)@indexentry(key="Procedure Parameters Ichan",entry="@ @ Ichan",number)
holds a channel number associated with the file to be used for input.  This file
should not be open (i.e., it should be the result of a call to one of GTJFN,
GTJFNL, @index(GTJFN Built-in SAIL Function)@index(GTJFNL Built-in SAIL Function)
cm!ifi, cm!ofi, cm!fil, or some other procedure that returns a channel number
without opening the file on that channel).  The ochan parameter
@index(Ochan Parameter)@indexentry(key="Procedure Parameters Ochan",entry="@ @ Ochan",number)
holds a channel number associated with the file to be used for output.  By output
we mean everything the user normally sees at his keyboard other than normal
input echoing (i.e. noise words, editing characters, help messages, etc.).
This file also should not be open.
The cm!take procedure will push the old JFNs on a stack and make those passed
for ichan and ochan the ones to be used in COMND calls from that point on.
When the file associated with ichan runs out, the old JFNs are automatically
popped back into use, and the cm!eof variable@index(Cm!Eof Variable)
@indexentry(key="Variables Cm!Eof",entry="@ @ Cm!Eof",number)
is set to true.

	The errpop parameter@index(Errpop Parameter)@indexentry(key="Procedure Parameters Errpop",entry="@ @ Errpop",number)
controls what action is taken when an error (other than end-of-file) occurs
while using the new JFNs.  If errpop is true, then upon encountering such
an error, the old JFNs are immediately popped back and if cm!minor and cm!major
allow it, an error message is printed.  Also the cm!abort variable
@index(Cm!Abort Variable)@indexentry(key="Variables Cm!Abort",entry="@ @ Cm!Abort",number)
is set to true.  If errpop is false, then the JFNs are popped only for end-of-file, and error messages will be printed as usual according to the values of
cm!minor and cm!major.

@Subsection(The Cm!Tbuild Procedure)
@index(Cm!Tbuild Procedure)@indexentry(key="Cm! - Procedures Cm!Tbuild",entry="@ @ Cm!Tbuild",number)@index(Building TBLUK Lookup Tables)@indexentry(key="TBLUK Lookup Table Building",entry="@ @ Building",number)
@Verbatim{
integer procedure cm!tbuild
	(string array keys;
	 reference integer array table);
}
	The cm!tbuild procedure converts a string array of keywords into
a TBLUK lookup table for use by the cm!key and cm!swi procedures (see the
description of the TBLUK jsys in the Monitor Calls Reference Manual for
details on the internals of a TBLUK lookup table).  The keywords are
passed by way of the 
@index(Keys Parameter)@indexentry(key="Procedure Parameters Keys",entry="@ @ Keys",number)
keys array, and the table is stored in the table
@indexentry(key="Procedure Parameters Table",entry="@ @ Table",number)@index(Table Parameter)
array.  If enough room was available in table to store the entire lookup
table, a 0 is returned by cm!tbuild.  Otherwise, a -1 is returned, and
chances are the lookup table is in an unacceptable format for cm!key and
cm!swi.  One convenient way to insure that enough room will be available
is by using the cm!size procedure (above).
	The keys parameter is a string array of keywords which are to
be inserted into the table, and need not be alphabetized. cm!tbuild will
not insert duplicate entries twice, and if two elements of keys are identical
it will place the index of the last duplicate entry found in the cm!err
variable.  
	Each string in keys may be prefixed by either or both of two
@index(Punctuation In TBLUK Lookup Tables)@indexentry(key="TBLUK Lookup Table Special Punctuation",entry="@ @ Special Punctuation",number)
punctuation characters.  If  a "%" character appears within the first two
@index(Invisible Keywords)@indexentry(key="TBLUK Lookup Table Invisible Entries",entry="@ @ Invisible Entries",number)
characters of a string the CM%INV (INV = INVisible) bit will be turned on for the corresponding
entry in the lookup table.  The effect of this is that the keyword will
not appear in the standard help message of the CMKEY or CMSWI function
calls. In this way it is essentially "invisible" to the user.
@index(Ignored Keywords)@indexentry(key="TBLUK Lookup Table Ignored Entries",entry="@ @ Ignored Entries",number)
	If a "#" character appears within the first two characters of a string
in the keys array, the CM%NOR (NOR = igNORe) bit will be turned on in the corresponding
lookup table entry.  Its effect is such that the corresponding keyword
will be "invisible" as above, but it will also not be recognized, even
if an exact match is typed by the user.  Thus the keyword is effectively
"ignored" by cm!key and cm!swi.  This is useful when you wish to rule
out an abbreviation.  For instance, if you wish the user to be required
to type at least "MINIM" as an abbreviation for "MINIMAL", you could
include the string "#MINI" as one of the strings in the keys array, and
the desired result would be achieved.
	Note that the cm!tbuild procedure does not include a facility for
@Index(Keyword Abbreviations)@indexentry(key="TBLUK Lookup Table Abbreviated Entries",entry="@ @ Abbreviated Entries",number)
setting the CM%ABR (ABR = ABbReviation) bit in a lookup table entry.  For
information on what this bit does, see the description of the CMKEY function
call of the COMND jsys in the Monitor Calls Reference Guide.  It is possible
for wizards to set this bit themselves, but they should read the description
of the TBLUK jsys in the Monitor Calls Reference Guide, as well as the
"Note to Wizards" in the description of the cm!key procedure above.

@Subsection(The Cm!Tok Procedure)
@index(Cm!Tok Procedure)@indexentry(key="Cm! - Procedures Cm!Tok",entry="@ @ Cm!Tok",number)@index(Token Fields)
@Verbatim{
boolean procedure cm!tok
	(string token,
	        help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
The cm!tok procedure performs the @indexentry(key="COMND Functions CMTOK",entry="@ @ CMTOK",number)
CMTOK (TOK = TOKen) function call of the COMND jsys.  This procedure is used to
test whether or not the string passed for the token parameter@index(Token Parameter)
@indexentry(key="Procedure Parameters Token",entry="@ @ Token",number)
matches the characters that appear next in the input buffer.  The procedure
returns true if the string matches, false otherwise.  There is no standard
help message for CMTOK.@indexentry(key="Standard Help Message CMTOK",entry="@ @ CMTOK",number)

@Subsection(The Cm!Txt Procedure)
@index(Cm!Txt Procedure)@indexentry(key="Cm! - Procedures Cm!Txt",entry="@ @ Cm!Txt",number)@index(Text Fields)
@Verbatim{
string procedure cm!txt
	(string help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false);
	 string brchars(null));
}
	The cm!txt procedure performs the 
@indexentry(key="COMND Functions CMTXT",entry="@ @ CMTXT",number)
CMTXT (TXT = TeXT) function call
of the COMND jsys.  It returns all text typed by the user up to but not
including the next carriage return. 
The standard help message for the CMTXT function
@indexentry(key="Standard Help Message CMTXT",entry="@ @ CMTXT",number)
call is "TEXT STRING".

@indexentry(key="Standard Break Characters CMTXT",entry="@ @ CMTXT",number)
	The standard break table for CMTXT is as follows:
@verbatim{
		ASCII Codes	Description
		  12		Linefeed
		  15		Carriage Return
}

@Subsection(The Cm!Uqs Procedure)
@index(Cm!Uqs Procedure)@indexentry(key="Cm! - Procedures Cm!Uqs",entry="@ @ Cm!Uqs",number)@index(Unquoted String Fields)
@Verbatim{
string procedure cm!uqs
	(string brchars;
	 string help(null),def(null);
	 boolean raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
The cm!uqs procedure performs the CMUQS (UQS = UnQuoted String)
@indexentry(key="COMND Functions CMUQS",entry="@ @ CMUQS",number)
function call of the COMND jsys.  This procedure is used for parsing
a string field with arbitrary break characters.  The procedure will
return all characters typed up to, but not including the first break
character typed.  Note that
all action characters lose their special meaning unless they are included in
the brchars string.@index(Action Characters)  
@indexentry(key="Standard Help Message CMUQS",entry="@ @ CMUQS",number)
There is no standard help message for CMUQS.

@Subsection(The Cm!Usr Procedure)
@index(Cm!Usr Procedure)@indexentry(key="Cm! - Procedures Cm!Usr",entry="@ @ Cm!Usr",number)@index(User Name Fields)
@Verbatim{
integer procedure cm!usr
	(string help(null),def(null);
	 boolean sup$help(false),
		 raise$input(false),
		 no$indirect(false),
		 wake$always(false),
		 parse$only(false));
}
	The cm!usr procedure performs the 
@indexentry(key="COMND Functions CMUSR",entry="@ @ CMUSR",number)
CMUSR (USR = USeR) function call of the COMND
jsys.  It is almost identical to the cm!dir procedure, except that user names
are not surrounded by angle brackets  ("<>") as are directory names.  Also, there
is no allow$wild parameter, since wildcards do not make sense with user names.
A user number is returned by the procedure, which may be tranlated into a user
name string via SAIL's @index(DIRST Built-in SAIL Function)DIRST built-in procedure.  The standard help message for
@indexentry(key="Standard Help Message CMUSR",entry="@ @ CMUSR",number)
the CMUSR function call is "USER NAME".

@Section(Multiple FDBs)

	It was mentioned in Part I of this document that it is possible to
give COMND several alternatives from which to choose in a single call.  This
section of the document describes the implementation and use of this feature
in the SAIL-COMND interface package.

@index(FDB Chain)
	Room is set aside for building a chain of up to ten FDB's to be
used in a call to COMND.  These FDB's are set up by using procedures which
parallel those just described in Section 2.  Each of the cm! procedures which
actually calls the COMND jsys into action (all but cm!getatm, cm!retry,
cm!size, cm!take and cm!tbuild) has a companion procedure whose name starts with
@indexentry(key="Cm# - Procedures zzz",entry="@ @ (All Others)",number)
@index(Cm# - Procedures)"cm#" instead of "cm!"  (thus cm!key becomes cm#key, etc.). These cm# procedures
are called in exactly the same way as the corresponding cm! procedures, except
that all def, raise$input, no$indirect and wake$always parameters are left
off.  Each procedure returns an integer: 0 if there was room in the multiple
FDB block to set up the new FDB, and -1 otherwise (10 FDB's max). The FDB's are linked together in the order in which the procedures are
called.  Thus if the program calls first cm#key, then cm#usr, then cm#tad,
COMND will try first to match a keyword, then a user name, then a time and
date.  COMND will stop as soon as one of the FDB's caused a success.  If
none of them succeeds, cm!err will be set to the error code appropriate to
the last FDB tried.

	Before starting to set up the FDB's, however, the program should
@index(Cm#Reset Procedure)@indexentry(key="Cm# - Procedures Cm#Reset",entry="@ @ Cm#Reset",number)
issue a call to the cm#reset procedure (no arguments, no value returned),
which initializes the multiple FDB block.

	After all the FDB's have been set up, the program issues a call to
@index(Cm#Call Procedure)@indexentry(key="Cm# - Procedures Cm#Call",entry="@ @ Cm#Call",number)
the cm#call procedure, whose procedure definition header is as follows:
@Verbatim{
integer procedure cm#call
	(string def(null);
	 boolean raise$input(false),
		 no$indirect(false),
		 wake$always(false));
}
Here the parameters are the same as they were in the cm! procedures, but
they  apply to all the FDB's taken as a whole.  The cm#call procedure
returns an integer which indicates which FDB was successful, according
to the order in which the FDB's were set up (1 is the first).  The
result of the parsing will always be a string, an integer, or a real number.
Upon completion of the cm#call procedure, this result will be found in one of
@index(Cm#Str Variable)@index(Cm#Int Variable)@index(Cm#Real Variable)
@indexentry(key="Variables Cm#Str",entry="@ @ Cm#Str",number)
@indexentry(key="Variables Cm#Int",entry="@ @ Cm#Int",number)
@indexentry(key="Variables Cm#Real",entry="@ @ Cm#Real",number)
three variables corresponding to these types: cm#str (for strings), 
cm#int (for integers), or cm#real (for real numbers).
It is up to the calling program to determine (via the integer returned by
cm#call) where to look for the response.  Thus if a CMKEY function call
succeeds the program should look in the cm#int variable.  If a CMQST function
call succeeds, the program should look in the cm#str variable.
@chapter(Examples)
@Section(Example 1 - Nothing Fancy)

	This example does nothing fancy, but then, many real applications
are that way.  The example is a routine that could be used to perform
the parsing for the TERMINAL command of the EXEC. @index(EXEC)@index(TERMINAL command)
The routine would be called by the main parsing routine when 
the keyword "terminal" is parsed.  This routine should return upon a
reparse or error condition, or upon a completed command.  Note that
the code for actually performing the various tasks is not included here,
but it is indicated by the various block names where such code should go.

@subsection(SAIL Code)

@begin(verbatim)
******************** Start of Example 1 ********************

! Set up the keyword and noise word tables to be used;

Preload!With
  "flag","formfeed","immediate","indicate","lowercase",
  "raise","tabs","page","halfduplex","line-halfduplex",
  "fullduplex","length","speed","width","help","no","type",
  "33","35","37","bantam","concept-100","datamedia-1520",
  "execuport","glass-tty","la30","la36","perkin-elmer-1100",
  "system-default","terminet","ti","ti733","vt05","vt50",
  "vt52";
  String Array ModeKeys[1:35];	! Keywords to select mode;

Preload!With
  "0","50","75","110","134","150","200","300","600","1200",
  "1800","2400","4800","9600";
  String Array SpeedKeys[1:14];	! Allowable Terminal Speeds;

Preload!With
  "flag","formfeed","immediate","indicate","lowercase",
  "raise","tabs","page";
  String Array NoKeys[1:8];	! Allowable Keywords after
				! "no" keyword;

Preload!With
  "33","35","37","bantam","concept-100","datamedia-1520",
  "execuport","glass-tty","la30","la36","perkin-elmer-1100",
  "system-default","terminet","ti","ti733","vt05","vt50",
  "vt52";
  String Array TypeKeys[18:35];	! Possible keywords after;
				! 'type' keyword (indices ;
				! chosen to match ModeKeys);
Preload!With
  "upper case output","exists on terminal","echo mode",
  "formfeed","exists on terminal","terminal input",
  "exist on terminal","mode","mode for terminal",
  "mode for terminal","mode for terminal","of page is",
  "of input","of line is";
  String Array Noises[1:14];	! Noise words for ModeKeys
				! and NoKeys;

Procedure Ter!Comm;
  Begin "Parse a 'Terminal' command line"

    ! Miscellaneous declarations;
    Integer ModeNo, ISpeed, OSpeed, PLen, PWid;
    Integer TOption, TType;
    Boolean ModeOn;	! False if a 'no ...' command;
    Boolean NoLen;	! True if no len was specified;
			! on a 'terminal page' command;
    ! Declarations for keyword tables;
@indexentry(key="Cm!Size Procedure Example of Use",entry="@ @ Example of Use",number)
    Integer Array ModeTab[0:cm!size(ModeKeys)];
    Integer Array SpeedTab[0:cm!size(SpeedKeys)];
    Integer Array NoTab[0:cm!size(NoKeys)];
    Integer Array TypeTab[0:cm!size(TypeKeys)];

    ! Build the TBLUK Lookup Tables;
@indexentry(key="Cm!Tbuild Procedure Example of Use",entry="@ @ Example of Use",number)
    cm!tbuild(ModeKeys,ModeTab);
    cm!tbuild(SpeedKeys,SpeedTab);
    cm!tbuild(NoKeys,NoTab);
    cm!tbuild(TypeKeys,TypeTab);

@indexentry(key="Cm!Noi Procedure Example of Use",entry="@ @ Example of Use",number)
    cm!noi("mode is");	! Noise word for 'terminal' command;
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
    If cm!err or cm!reparse then return;

    ModeOn := true;	! Until we get a 'no' command;
@indexentry(key="Cm!Key Procedure Example of Use",entry="@ @ Example of Use",number)
    ModeNo := cm!key(ModeTab);	! Get the desired mode;
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
    If cm!err or cm!reparse then return;

    ! First 14 modes require noise word next;

    If Modeno leq 14 then
      Begin "Noise"
@indexentry(key="Cm!Noi Procedure Example of Use",entry="@ @ Example of Use",number)
	cm!noi(Noises[ModeNo]);
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	If cm!err or cm!reparse then return;
      End "Noise";


    ! Now treat any that require more fields;

    Case ModeNo of
      Begin "Extra Parsing"

	[8] Begin "Page Mode"
	      ! Possible next field for page length;
	      ! Turn off minor error messages in case
	      ! length is not given;
@indexentry(key="Cm!Minor Variable Example of Use",entry="@ @ Example of Use",number)
	      cm!minor := false;
@indexentry(key="Cm!Num Procedure Example of Use",entry="@ @ Example of Use",number)
	      PLen := cm!num
	       ("Carriage return or page length",null,true);
	      ! Now turn minor error messages back on;
	      cm!minor := true;
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!reparse then return;
	      ! Signal whether or not page was specified -;
	      ! if it wasn't we'll try a cm!cfm later on;
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
	      NoLen := cm!err;
	    End "Page Mode";

	[12]Begin "Length Mode"
	      ! We get a page length next;
@indexentry(key="Cm!Num Procedure Example of Use",entry="@ @ Example of Use",number)
	      PLen := cm!num
		("Length of page in decimal",null,true);
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!err or cm!reparse then return;
	    End "Length Mode";

	[13]Begin "Speed Mode"
	      ! We get an input speed first;
@indexentry(key="Cm!Key Procedure Example of Use",entry="@ @ Example of Use",number)
	      ISpeed := cm!key(SpeedTab);
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!err or cm!reparse then return;

	      ! Now a noise word;
@indexentry(key="Cm!Noi Procedure Example of Use",entry="@ @ Example of Use",number)
	      cm!noi("and output");
	      If cm!err or cm!reparse then return;

	      ! Now get an output speed;
	      ! Default is same as input speed;
@indexentry(key="Cm!Key Procedure Example of Use",entry="@ @ Example of Use",number)
	      OSpeed := cm!key
		(SpeedTab,null,SpeedKeys[ISpeed]);
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!err or cm!reparse then return;

	    End "Speed Mode";

	[14]Begin "Width Mode"
	      ! We get a page width;
@indexentry(key="Cm!Num Procedure Example of Use",entry="@ @ Example of Use",number)
	      PWid := cm!num
	       ("Terminal line width in decimal",null,true);
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!err or cm!reparse then return;
	    End "Width Mode";

	[16]Begin "No ... Mode"
	      ! Find out what he doesn't want;
@indexentry(key="Cm!Key Procedure Example of Use",entry="@ @ Example of Use",number)
	      ModeNo := cm!key(NoTab);
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!err or cm!reparse then return;

	      ! Put out a noise word;
@indexentry(key="Cm!Noi Procedure Example of Use",entry="@ @ Example of Use",number)
	      cm!noi(Noises[ModeNo]);
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!err or cm!reparse then return;

	      ! Reset flag to indicate 'no';
	      ModeOn := false;
	    End "No ... Mode";

	[17]Begin "Type Mode";
	      ! We get either a type number or name;
	      ! Use multiple FDBs to parse this field;
	      ! Default is 'system-default';

@indexentry(key="Multiple Function Calls Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm#Reset Procedure Example of Use",entry="@ @ Example of Use",number)
	      cm#reset;	! Clear the multiple FDBs;
@indexentry(key="Cm#Key Procedure Example of Use",entry="@ @ Example of Use",number)
	      cm#key(TypeTab);
@indexentry(key="Cm#Num Procedure Example of Use",entry="@ @ Example of Use",number)
	      cm#num("Terminal type",true);
@indexentry(key="Cm#Call Procedure Example of Use",entry="@ @ Example of Use",number)
	      TOption := cm#call("system-default");
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
	      If cm!err or cm!reparse then return;

	      ! If user typed one of the strings in;
	      ! TypeKeys, then pretend that the user;
	      ! never even typed the word 'type';
@indexentry(key="Cm#Int Variable Example of Use",entry="@ @ Example of Use",number)
	      If TOption = 1 then ModeNo := cm#int

	      ! Otherwise, set the TType variable;
@indexentry(key="Cm#Int Variable Example of Use",entry="@ @ Example of Use",number)
	      Else TType := cm#int;
	    End "Type Mode";

	Else ! Do nothing more for other modes;

      End "Extra Parsing";

    ! Now the command line is almost complete - only;
    ! thing left to do is confirm;
@indexentry(key="Cm!Cfm Procedure Example of Use",entry="@ @ Example of Use",number)
    cm!cfm;
@indexentry(key="Cm!Err Variable Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm!Reparse Variable Example of Use",entry="@ @ Example of Use",number)
    If cm!err or cm!reparse then return;

    ! We have an acceptable command line - now implement it;

    Case ModeNo of
      Begin "Execute the command"

	[1] Begin "flag"
	      ! Code to set flag mode goes here;
	    End "flag";

	[2] Begin "formfeed"
	      ! Code to set formfeed mode goes here;
	    End "formfeed";

		.
		.
		.

	[35]Begin "vt52"
	      ! Code to set terminal vt52 goes here;
	    End "vt52"

      End "Execute the command";

    ! We are all finished - now return successfully;
    Return;

  End "Parse a 'Terminal' command line";

********************* End of Example 1 *********************

@end(verbatim)

@subsection(Remarks)
@begin(enumerate)
@index(Building TBLUK Lookup Tables)@indexentry(key="TBLUK Lookup Table Building",entry="@ @ Building",number)
The keyword tables are built every time the Ter!Comm procedure is called.
This is quite wasteful, and in most applications the keyword tables will
all be built in an outside block only once, and will never need to be
rebuilt.  There are two prevalent ways of doing this:
@begin(itemize)
The keyword table
array may be declared with fixed bounds in the programs outer block.  In
this case, the cm!size procedure will not be used as it was in the example.
The advantage of this method is that the array is static and can be declared
in the same block as the string array containing the keywords.  The disadvantage
is that the fixed bounds may have to be altered if a new keyword needs to be
added to the table.

The string arrays for the tables may be declared in the program's outer
block, and the table arrays may be declared in an inner block, using
the cm!size procedure to calculate upper array bounds.  The advantage
is that it is very easy to add a new keyword to the table.  The disadvantages
are the extra time required for computing the bound and allocating the array,
and the extra level of nesting that will probably result.

@end(itemize)

All the parsing was done prior to the execution of the command.  An alternative
method would be to execute each command as soon as it is determined (e.g. in
the above example, we could have included a cm!cfm and the code for setting
page mode within the "Page Mode" block, etc.).  The disadvantage of this is
that it makes the parsing process more difficult to follow.  Sometimes,
however, this method is unavoidable where the results of some action taken
on one field can change some parsing parameters of a following field.

In this example reparse and error conditions were treated identically.
This is because the cm!ini and the first field of the line were both
taken care of by the calling routine, so the action for either condition
would have to start there.  The calling routine can easily check the values
of cm!err and cm!reparse immediately following the call to Ter!Comm.

@index(CASE Statement In SAIL)
The Case statement almost always accompanies the use of cm!key or cm#key,
and often will go along with any multiple FDB uses.

@index(Changing Contents of TBLUK Lookup Tables)
@indexentry(key="TBLUK Lookup Table Changing Contents",entry="@ @ Changing Contents",number)
Although in this example all the keywords were in preloaded arrays whose
contents were never changed, this need not be the case.  Keyword arrays
may change in any way desired, and tables rebuilt from them.  Do not forget
to rebuild the table arrays, however; the changes will not show up in
the COMND calls that use the tables until they are.

It is easy to finish reading part II with the impression that the routines
in the interface are very complicated and difficult to use, since they all
seem to have so many parameters.  This is a false impression, however, as
this example and those that follow demonstrate.  The reason is that almost
@index(Optional Parameters)
all the parameters used in the interface routines are optional parameters
that are rarely specified.

A complete program that uses the Ter!Comm procedure and merely reports
what it finds exists as sai:tercom.sai and sai:tercom.exe.
@index(TERCOM Sample Program)
@end(enumerate)
@section(Example 2 - The Ctrl/H Feature And Switches)
In this example we see how to go about using the ctrl/h feature (see section
@ref(ctrl/hfea), page @pageref(ctrl/hfea)) of COMND in SAIL programs.
Also, a technique is given for parsing a list of similar objects separated
by commas.

The command line is one that might be used for a crude mail sending program.
There are two commands: exit and send.  The exit command causes the program
to halt.  The send command takes as its second field an input file name where
a message is stored, and then a list of switches.  Possible switches are
/to, /cc, and /subject.  The /to and /cc switches both take as arguments
a list of userids separated by commas.  The /subject switch takes a
quoted string as an argument.  The switches may be intermingled as
desired, and any switch may be used more than once.  If the /subject
switch is used more than once, the old subject string is discarded.  If
the /to or /cc switch is used more than once, the new list is tacked onto
the old list.

@subsection(SAIL Code)

@begin(verbatim)
******************** Start of Example 2 ********************

Begin "Compost"

 require "sai:comnd.hdr" source!file;
 require "{}{}" delimiters;
 define ! = {comment};

 ! "Compost" stands for "Computer Post Office";

 ! Declare keyword arrays;
 Preload!With "send", "exit";
  String Array Commands[1:2];
 Preload!With "to:","cc:","subject:";
  String Array Switches[1:3];
 ! Now descend into another block so we can dynamically;
 ! allocate the table arrays;

 Begin "Main Level"
  ! Declare the table arrays;
@indexentry(key="Cm!Size Procedure Example of Use",entry="@ @ Example of Use",number)
  Integer Array Comm!Tab[0:cm!size(commands)];
  Integer Array Swit!Tab[0:cm!size(switches)];

  ! Declare a record class to hold linked lists of;
  ! message recipients, along with list head pointers;
  Record!Class Recips(Integer Userid;
		      Record!Pointer(Recips) Next);
  Record!Pointer(Recips) To!List, Cc!List;

  ! Integer to hold channel number for message file;
  Integer Channel;

  ! String to hold subject of message;
  String Subject;

  ! Boolean determines whether or not ctrl/h feature is
  ! activated on each call to cm!ini (activated if false);
  Boolean Ctrl!H!Off;

  ! Other miscellaneous variables;
  Integer Comm!No, Swit!No, Option, Userid;
  Record!Pointer(Recips) Temp;

  ! Build the lookup tables;
@indexentry(key="Cm!Tbuild Procedure Example of Use",entry="@ @ Example of Use",number)
  cm!tbuild(Commands,Comm!Tab);
  cm!tbuild(Switches,Swit!Tab);

  ! Initialize Ctrl!H!Off to deactivate ctrl/h feature;
  Ctrl!H!Off := true;

  ! A useful definition;
  Define Check =
	{If cm!err then continue "outer loop";
	 If cm!reparse then continue "inner loop"};

  ! Now go parse the command line;

  While true do
   Begin "outer loop"

    ! Issue the prompt and set up the command line;
@indexentry(key="Cm!Ini Procedure Example of Use",entry="@ @ Example of Use",number)
    cm!ini("Compost> ", Ctrl!H!Off);

    ! Set Ctrl!H!Off so that ctrl/h feature will be;
    ! activated if we come here again due to an error.;
    ! If we return from a successful command line, the;
    ! variable should be reset before we get here;
    Ctrl!H!Off := false;

    While true do
     Begin "inner loop"

      ! Release any currently unopened JFN. It is;
      ! the result of an error after the JFN;
      ! has already been obtained;
      Start!code "release"
	hrroi	1,-1;
	Rljfn;
	Haltf;
      End "release";

      ! Clear the recipients lists;
      To!List := Cc!List := Null!Record;

      ! Get a command;
@indexentry(key="Cm!Key Procedure Example of Use",entry="@ @ Example of Use",number)
      Comm!No := cm!key(Comm!Tab);
      Check;	! Checks for error and reparse;

      ! Halt on 'exit' command;
      If Comm!No = 2 then
       Begin "exit"
@indexentry(key="Cm!Cfm Procedure Example of Use",entry="@ @ Example of Use",number)
	cm!cfm;
	Check;
	While true do Start!code Haltf End;
       End "exit";

      ! Otherwise, 'send' command - guide word next;
@indexentry(key="Cm!Noi Procedure Example of Use",entry="@ @ Example of Use",number)
      cm!noi("message file");
      Check;

      ! Now get an input file specification;
@indexentry(key="Cm!Ifi Procedure Example of Use",entry="@ @ Example of Use",number)
      Channel := cm!ifi;
      Check;

      ! Now parse any switches;
      ! May also get a carriage return, so use ;
      ! multiple FDB's;

      While true do
       Begin "Parse Switch"
	! Use multiple FDBs for either carriage;
	! return or a switch;

	! Reset the multiple FDB chain;
@indexentry(key="Multiple Function Calls Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm#Reset Procedure Example of Use",entry="@ @ Example of Use",number)
	cm#reset;

	! Now build the a new chain;
@indexentry(key="Cm#Swi Procedure Example of Use",entry="@ @ Example of Use",number)
	cm#swi(Swit!Tab);
@indexentry(key="Cm#Cfm Procedure Example of Use",entry="@ @ Example of Use",number)
	cm#cfm;

	! Get next field;
@indexentry(key="Cm#Call Procedure Example of Use",entry="@ @ Example of Use",number)
	Option := cm#call;
	Check;

	! If cm#cfm then we're through;
	If Option = 2 then Done "inner loop";

	! If no colon after switch, get another one;
@indexentry(key="Cm!Colon Variable Example of Use",entry="@ @ Example of Use",number)
	If not cm!colon then continue "Parse Switch";

	! Otherwise, process the switch;
@indexentry(key="Cm#Int Variable Example of Use",entry="@ @ Example of Use",number)
	Swit!No := cm#int;
	While true do
	 Begin "Process Switch"
	  Case Swit!No of
	   Begin "Pick a Switch"
	    [1] [2]
	     Begin "Get userid list"
	      ! Now we need a userid list;
	      While true do
	       Begin "Get a userid"
		! Get one userid;
@indexentry(key="Cm!Usr Procedure Example of Use",entry="@ @ Example of Use",number)
		Userid := cm!usr;
		Check;

		! Allocate a record to hold new userid;
		Temp := New!Record(Recips);
		Recips:Userid[Temp] := Userid;

		! Tack it onto the appropriate list;
		If Swit!No = 1 then
		 Begin "New to"
		  Recips:Next[Temp] := To!List;
		  To!List := Temp;
		 End "New to";

		If Swit!No = 2 then
		 Begin "New cc"
		  Recips:Next[Temp] := Cc!List;
		  Cc!List := Temp;
		 End "New cc";

		! Now get a comma, a new switch,;
		! or a carriage return;
@indexentry(key="Multiple Function Calls Example of Use",entry="@ @ Example of Use",number)
@indexentry(key="Cm#Reset Procedure Example of Use",entry="@ @ Example of Use",number)
		cm#reset;
@indexentry(key="Cm#Cma Procedure Example of Use",entry="@ @ Example of Use",number)
		cm#cma;
@indexentry(key="Cm#Swi Procedure Example of Use",entry="@ @ Example of Use",number)
		cm#swi(Swit!Tab);
@indexentry(key="Cm#Cfm Procedure Example of Use",entry="@ @ Example of Use",number)
		cm#cfm;
@indexentry(key="Cm#Call Procedure Example of Use",entry="@ @ Example of Use",number)
		Option := cm#call;
		Check;

		! if cm#cfm was used, we're done;
		If Option = 3 then done "inner loop";

		! if cm#cma was used, get another userid;
		If Option = 1 then continue "Get a userid";

		! if cm#swi without colon, ignore switch;
@indexentry(key="Cm!Colon Variable Example of Use",entry="@ @ Example of Use",number)
		If not cm!colon then
		  continue "Parse Switch";

		! Otherwise, process the switch;
@indexentry(key="Cm#Int Variable Example of Use",entry="@ @ Example of Use",number)
		Swit!No := cm#int;
		Continue "Process Switch";

	       End "Get a userid";
	     End "Get userid list";

	    [3]
	     Begin "Get subject string"
	      ! Use cm!qst to get quoted string;
@indexentry(Key="Cm!Qst Procedure Example of Use",entry="@ @ Example of Use",number)
	      Subject := cm!qst("Subject of message");
	      Check;

	      ! Now get next switch;
	      Continue "Parse Switch";
	     End "Get subject string"
	   End "Pick a Switch";
	 End "Process Switch";
       End "Parse Switch";
     End "inner loop";

    ! When we get here, we have successfully parsed a line;

    ! Deactivate ctrl/h feature for next time around;
    Ctrl!H!Off := true;

    ! Now process the request;
    Begin "Process Request"
	! Code for processing the request goes here;
    End "Process Request";

    ! Now we're ready for another line;

   End "outer loop";

 End "Main Level";

End "Compost"

********************* End of Example 2 *********************

@end(verbatim)

@subsection(Remarks)

@begin(enumerate)
The most important part of this example, other than demonstrating
the ctrl/h feature, the use of switches, and the accumulation of
a list of similar items, is the demonstration of a very widespread
style of writing a command line parser using the interface.  The general
format goes something like this:

@verbatim{

    While true do
      Begin "A"
	cm!ini( ... );
	While true do
	  Begin "B"
	     .
	     .
	     .
	    cm!xxx( ... );
	    if cm!err then continue "A";
	    if cm!reparse then continue "B";
	     .
	     .
	     .
	    cm!cfm;
	    if cm!err then continue "A";
	    if cm!reparse then continue "B";
	    Done "B";
	     .
	     .
	     .
	  End "B";
	.
	.  ! Process the command line;
	.
      End "A";


}
With this format the command line will be repeated immediately
after it is processed.  An alternative is to move everything between
'End "B";' and 'End "A";' outside of the "A" block and change the
'Done "B";' to 'Done "A";'.  This would be preferable if the command line
is not to be repeated after the current contents are processed.

Parsing a list of similar objects (userids, in the above example) can
be very difficult, and the form of the code will not always resemble
the code in Example 2 very closely.  The example is meant to give a
general idea of what is involved in a concrete framework.

In this example the table arrays were built using the second suggestion
of remark number one in Example 1.

As can be seen, nesting can get quite deep in a parsing routine that
uses the interface.  In Example 2, indenting of new levels had to be decreased
from two spaces (the author's normal style) to one space, just to fit the 
code within the page boundaries.

A complete program which interprets the command line of this example and
merely reports what it found exists as sai:compos.sai and sai:compos.exe.
@index(COMPOS Sample Program)
@indexentry(key="Break Characters Standard",entry="@ @ Standard",number)
@end(enumerate)
@appendix(Standard Break Tables)

Following is a chart of the complete ASCII character set, with twelve
columns indicating which characters are in the standard break tables for
each of the twelve COMND functions that use them.  Starred (*) columns
indicate that the break tables are user-changeable, and the interface
procedures corresponding to those functions include a brchars parameter.

@index(Standard Break Characters)
@begin(verbatim)
     |     |		C O M N D   F u n c t i o n	   |
ASCII|Gra- | C | C | C | C | C | C | C | C | C | C | C | C |
Code |phic | M | M | M | M | M | M | M | M | M | M | M | M |
(Dec)|     | A | D | D | F | F | I | K | O | S | T | U | U |
     |     | C | E | I | I | L | F | E | F | W | X | Q | S |
     |     | T | V | R | L | D | I | Y | I | I | T | S | R |
     |     |   | * |   |   | * |   | * |   | * | * | * |   |
------------------------------------------------------------
   0 | ^@@  | X | X | X | X | X | X | X | X | X |   |   | X |
   1 | ^A  | X | X | X | X | X | X | X | X | X |   |   | X |
   2 | ^B  | X | X | X | X | X | X | X | X | X |   |   | X |
   3 | ^C  | X | X | X | X | X | X | X | X | X |   |   | X |
   4 | ^D  | X | X | X | X | X | X | X | X | X |   |   | X |
   5 | ^E  | X | X | X | X | X | X | X | X | X |   |   | X |
   6 | ^F  | X | X | X | X | X | X | X | X | X |   |   | X |
   7 | ^G  | X | X | X | X | X | X | X | X | X |   |   | X |
   8 | ^H  | X | X | X | X | X | X | X | X | X |   |   | X |
   9 | ^I  | X | X | X | X | X | X | X | X | X |   |   | X |
  10 | ^J  | X | X | X | X | X | X | X | X | X | X |   | X |
  11 | ^K  | X | X | X | X | X | X | X | X | X |   |   | X |
  12 | ^L  | X | X | X | X | X | X | X | X | X |   |   | X |
  13 | ^M  | X | X | X | X | X | X | X | X | X | X |   | X |
  14 | ^N  | X | X | X | X | X | X | X | X | X |   |   | X |
  15 | ^O  | X | X | X | X | X | X | X | X | X |   |   | X |
  16 | ^P  | X | X | X | X | X | X | X | X | X |   |   | X |
  17 | ^Q  | X | X | X | X | X | X | X | X | X |   |   | X |
  18 | ^R  | X | X | X | X | X | X | X | X | X |   |   | X |
  19 | ^S  | X | X | X | X | X | X | X | X | X |   |   | X |
  20 | ^T  | X | X | X | X | X | X | X | X | X |   |   | X |
  21 | ^U  | X | X | X | X | X | X | X | X | X |   |   | X |
  22 | ^V  | X | X | X | X | X | X | X | X | X |   |   | X |
  23 | ^W  | X | X | X | X | X | X | X | X | X |   |   | X |
  24 | ^X  | X | X | X | X | X | X | X | X | X |   |   | X |
  25 | ^Y  | X | X | X | X | X | X | X | X | X |   |   | X |
  26 | ^Z  | X | X | X | X | X | X | X | X | X |   |   | X |
  27 | ESC | X | X | X | X | X | X | X | X | X |   |   | X |
  28 | ^\  | X | X | X | X | X | X | X | X | X |   |   | X |
  29 | ^]  | X | X | X | X | X | X | X | X | X |   |   | X |
  30 | ^^  | X | X | X | X | X | X | X | X | X |   |   | X |
  31 | ^_  | X | X | X | X | X | X | X | X | X |   |   | X |
     |     |		C O M N D   F u n c t i o n	   |
ASCII|Gra- | C | C | C | C | C | C | C | C | C | C | C | C |
Code |phic | M | M | M | M | M | M | M | M | M | M | M | M |
(Dec)|     | A | D | D | F | F | I | K | O | S | T | U | U |
     |     | C | E | I | I | L | F | E | F | W | X | Q | S |
     |     | T | V | R | L | D | I | Y | I | I | T | S | R |
     |     |   | * |   |   | * |   | * |   | * | * | * |   |
------------------------------------------------------------
  32 |space| X | X | X | X | X | X | X | X | X |   |   | X |
  33 |  !  | X | X | X | X | X | X | X | X | X |   |   | X |
  34 |  "  | X | X | X | X | X | X | X | X | X |   |   | X |
  35 |  #  | X | X | X | X | X | X | X | X | X |   |   | X |
  36 |  $  | X |   |   |   | X |   | X |   | X |   |   | X |
  37 |  %  |   | X |   |   | X |   | X |   | X |   |   |   |
  38 |  &  | X | X | X | X | X | X | X | X | X |   |   | X |
  39 |  '  | X | X | X | X | X | X | X | X | X |   |   | X |
  40 |  (  | X | X | X | X | X | X | X | X | X |   |   | X |
  41 |  )  | X | X | X | X | X | X | X | X | X |   |   | X |
  42 |  *  |   | X |   |   | X |   | X |   | X |   |   |   |
  43 |  +  | X | X | X | X | X | X | X | X | X |   |   | X |
  44 |  ,  | X | X | X | X | X | X | X | X | X |   |   | X |
  45 |  -  |   |   |   |   |   |   |   |   |   |   |   |   |
  46 |  .  |   | X |   |   | X |   | X |   | X |   |   |   |
  47 |  /  | X | X | X | X | X | X | X | X | X |   |   | X |
  48 |  0  |   |   |   |   |   |   |   |   |   |   |   |   |
  49 |  1  |   |   |   |   |   |   |   |   |   |   |   |   |
  50 |  2  |   |   |   |   |   |   |   |   |   |   |   |   |
  51 |  3  |   |   |   |   |   |   |   |   |   |   |   |   |
  52 |  4  |   |   |   |   |   |   |   |   |   |   |   |   |
  53 |  5  |   |   |   |   |   |   |   |   |   |   |   |   |
  54 |  6  |   |   |   |   |   |   |   |   |   |   |   |   |
  55 |  7  |   |   |   |   |   |   |   |   |   |   |   |   |
  56 |  8  |   |   |   |   |   |   |   |   |   |   |   |   |
  57 |  9  |   |   |   |   |   |   |   |   |   |   |   |   |
  58 |  :  | X | X |   |   | X |   | X |   | X |   |   | X |
  59 |  ;  | X | X |   |   | X |   | X |   | X |   |   | X |
  60 |  <  | X | X |   |   | X |   | X |   | X |   |   | X |
  61 |  =  | X | X | X | X | X | X | X | X | X |   |   | X |
  62 |  >  | X | X |   |   | X |   | X |   | X |   |   | X |
  63 |  ?  | X | X | X | X | X | X | X | X | X |   |   | X |
  64 |  @@  | X | X | X | X | X | X | X | X | X |   |   | X |
  65 |  A  |   |   |   |   |   |   |   |   |   |   |   |   |
  66 |  B  |   |   |   |   |   |   |   |   |   |   |   |   |
  67 |  C  |   |   |   |   |   |   |   |   |   |   |   |   |
  68 |  D  |   |   |   |   |   |   |   |   |   |   |   |   |
  69 |  E  |   |   |   |   |   |   |   |   |   |   |   |   |
  70 |  F  |   |   |   |   |   |   |   |   |   |   |   |   |
  71 |  G  |   |   |   |   |   |   |   |   |   |   |   |   |
  72 |  H  |   |   |   |   |   |   |   |   |   |   |   |   |
  73 |  I  |   |   |   |   |   |   |   |   |   |   |   |   |
  74 |  J  |   |   |   |   |   |   |   |   |   |   |   |   |
  75 |  K  |   |   |   |   |   |   |   |   |   |   |   |   |
  76 |  L  |   |   |   |   |   |   |   |   |   |   |   |   |
  77 |  M  |   |   |   |   |   |   |   |   |   |   |   |   |
  78 |  N  |   |   |   |   |   |   |   |   |   |   |   |   |
  79 |  O  |   |   |   |   |   |   |   |   |   |   |   |   |
     |     |		C O M N D   F u n c t i o n	   |
ASCII|Gra- | C | C | C | C | C | C | C | C | C | C | C | C |
Code |phic | M | M | M | M | M | M | M | M | M | M | M | M |
(Dec)|     | A | D | D | F | F | I | K | O | S | T | U | U |
     |     | C | E | I | I | L | F | E | F | W | X | Q | S |
     |     | T | V | R | L | D | I | Y | I | I | T | S | R |
     |     |   | * |   |   | * |   | * |   | * | * | * |   |
------------------------------------------------------------
  80 |  P  |   |   |   |   |   |   |   |   |   |   |   |   |
  81 |  Q  |   |   |   |   |   |   |   |   |   |   |   |   |
  82 |  R  |   |   |   |   |   |   |   |   |   |   |   |   |
  83 |  S  |   |   |   |   |   |   |   |   |   |   |   |   |
  84 |  T  |   |   |   |   |   |   |   |   |   |   |   |   |
  85 |  U  |   |   |   |   |   |   |   |   |   |   |   |   |
  86 |  V  |   |   |   |   |   |   |   |   |   |   |   |   |
  87 |  W  |   |   |   |   |   |   |   |   |   |   |   |   |
  88 |  X  |   |   |   |   |   |   |   |   |   |   |   |   |
  89 |  Y  |   |   |   |   |   |   |   |   |   |   |   |   |
  90 |  Z  |   |   |   |   |   |   |   |   |   |   |   |   |
  91 |  [  | X | X |   |   | X |   | X |   | X |   |   | X |
  92 |  \  | X | X | X | X | X | X | X | X | X |   |   | X |
  93 |  ]  | X | X |   |   | X |   | X |   | X |   |   | X |
  94 |  ^  | X | X | X | X | X | X | X | X | X |   |   | X |
  95 |  _  | X |   | X | X | X | X | X | X | X |   |   | X |
  96 |  `  | X | X | X | X | X | X | X | X | X |   |   | X |
  97 |  a  |   |   |   |   |   |   |   |   |   |   |   |   |
  98 |  b  |   |   |   |   |   |   |   |   |   |   |   |   |
  99 |  c  |   |   |   |   |   |   |   |   |   |   |   |   |
 100 |  d  |   |   |   |   |   |   |   |   |   |   |   |   |
 101 |  e  |   |   |   |   |   |   |   |   |   |   |   |   |
 102 |  f  |   |   |   |   |   |   |   |   |   |   |   |   |
 103 |  g  |   |   |   |   |   |   |   |   |   |   |   |   |
 104 |  h  |   |   |   |   |   |   |   |   |   |   |   |   |
 105 |  i  |   |   |   |   |   |   |   |   |   |   |   |   |
 106 |  j  |   |   |   |   |   |   |   |   |   |   |   |   |
 107 |  k  |   |   |   |   |   |   |   |   |   |   |   |   |
 108 |  l  |   |   |   |   |   |   |   |   |   |   |   |   |
 109 |  m  |   |   |   |   |   |   |   |   |   |   |   |   |
 110 |  n  |   |   |   |   |   |   |   |   |   |   |   |   |
 111 |  o  |   |   |   |   |   |   |   |   |   |   |   |   |
 112 |  p  |   |   |   |   |   |   |   |   |   |   |   |   |
 113 |  q  |   |   |   |   |   |   |   |   |   |   |   |   |
 114 |  r  |   |   |   |   |   |   |   |   |   |   |   |   |
 115 |  s  |   |   |   |   |   |   |   |   |   |   |   |   |
 116 |  t  |   |   |   |   |   |   |   |   |   |   |   |   |
 117 |  u  |   |   |   |   |   |   |   |   |   |   |   |   |
 118 |  v  |   |   |   |   |   |   |   |   |   |   |   |   |
 119 |  w  |   |   |   |   |   |   |   |   |   |   |   |   |
 120 |  x  |   |   |   |   |   |   |   |   |   |   |   |   |
 121 |  y  |   |   |   |   |   |   |   |   |   |   |   |   |
 122 |  z  |   |   |   |   |   |   |   |   |   |   |   |   |
 123 |  {  | X | X | X | X | X | X | X | X | X |   |   | X |
 124 |  |  | X | X | X | X | X | X | X | X | X |   |   | X |
 125 |  }  | X | X | X | X | X | X | X | X | X |   |   | X |
 126 |  ~  | X | X | X | X | X | X | X | X | X |   |   | X |
 127 | DEL | X | X | X | X | X | X | X | X | X |   |   | X |
@end(verbatim)