%% Documentation for RegUtil

%  The contents of this file are subject to the Mozilla Public License
%  Version 1.0 (the "License"); you may not use this file except in
%  compliance with the License. You may obtain a copy of the License at
%  http://www.mozilla.org/MPL/

%  Software distributed under the License is distributed on an "AS IS"
%  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
%  License for the specific language governing rights and limitations
%  under the License.

%  The Original Code is regutil.

%  The Initial Developer of the Original Code is Patrick TJ McPhee.
%  Portions created by Patrick McPhee are Copyright © 1999, 2001
%  Patrick TJ McPhee. All Rights Reserved.

%  Contributors:

% $Header: /netlabs.cvs/osfree/src/REXX/libs/rexxutil/regutil.tex,v 1.1.1.1 2003/10/04 08:36:02 prokushev Exp $


\documentclass{article}

% if run through pdftex, use ps fonts and turn on hyperlinking
\ifx\pdfoutput\undefined
 \def\rarrow{\ensuremath{\to}}
 \def\hyperlink#1#2{}
 \def\href#1#2{}
\else
 \usepackage[pdftex,pdfborder=0 0 0]{hyperref}
 % uncomment for older hyperref (or update your hyperref!)
 % \def\pdfBorderAttrs{/Border [0 0 0]}%
 \def\_{\textunderscore\penalty\hyphenpenalty}
 \usepackage{times}
 \font\symbol=psyr
 \def\rarrow{{\symbol\char174}}
 \pdfinfo { /Title (The Regina Rexx Interpreter -- Rexx Utility Functions)
  /Author (Patrick TJ McPhee)
  /Subject (Regutil User Guide)
  /Keywords (rexx,regina,rexxutil,regutil,system functions)
 }
\fi

\makeatletter
\def\verbatim@font{\normalfont\ttfamily\small}
\makeatother


\usepackage{makeidx}

\makeindex

\newtoks\rcmsg

\begin{document}
\let\thepage\relax

\title{The Regina Rexx Interpreter -- Rexx Utility Functions}
\author{Patrick TJ McPhee (ptjm@interlog.com)\\
        DataMirror Corporation}
\date{Version 1.1.9, 1 January 2002}

\maketitle

\eject
\setcounter{page}{1}
\pagenumbering{roman}

\tableofcontents

\vfil\eject
\setcounter{page}{1}
\pagenumbering{arabic}

\section{Introduction}

This paper describes an implementation of IBM's Rexx Utility functions
for Unix and Windows/NT. The Rexx Utility functions extend the
capabilities of Rexx programs in useful ways, and it's desirable to
have compatible interfaces available for all implementations. This
implementation is meant for the Regina interpreter, however it should
also work with other interpreters. An earlier version of the library
was binary compatible with Rexx/IMC\index{Rexx/IMC} on Solaris.

Although I have access to the rexxutil source code through the
OS/2 developer's kit, this implementation contains new code, and
is based on the documentation for IBM's implementation, rather than
its internals. The routines here are generally compatible\index{compatibility}
with IBM's,
although some IBM\index{IBM} functions or options are not implemented, and in some
cases, the regutil version provides minor enhancements. Please see the
file status.txt\index{completeness} in the distribution for claims of completion.

The manual, and the source code, are divided along the lines of
functionality, the major groupings being housekeeping
(regutil.c), file system (regfilesys.c), system
(regini.c), macro-space manipulation (regmacrospace.c),
stem manipulation (regstem.c),
console I/O (regscreen.c, regscreenux.c), and semaphore handling (regsem.c,
regsemux.c).

\subsection{Reporting Bugs}

\begin{enumerate}
\item[Theorem A:]Every program can be reduced by at least one line.
\item[Theorem B:]Every program contains at least one bug.
\item[Corollary:]Every program can be reduced to one line which doesn't work correctly.
\end{enumerate}

Regutil undergoes very little testing before new releases are shipped. I
have not had the time to produce a regression test, for instance,
and although it is on my list of things to do, the pressures of work and
life keep me from doing it.
Since the first `full' release of Regutil (1.0.4) in February 1999, there have
been surprisingly few bugs discovered, given the amount of testing it
undergoes at this end. When bugs are reported, I do my best to fix them
and to get a new release out within a short time. My time tends to be
very tight, though, so I can't make any guarantees.

If you do find a bug, an error in the documentation, or you simply have
a suggestion for improving the distribution, please send me details 
at ptjm@interlog.com. It's useful to know the operating system you're
using, the version of Regina (or Rexx/IMC), and the version of regutil,
and to have a set of steps for reproducing the bug.

If you are using regutil for a serious purpose and therefore take the
time to produce a test suite for your own use, I would appreciate it
if you'd contribute it to the cause.

\subsection{Using RxAddFunc}

All the routines in RegUtil can be loaded either directly using
RxFuncAdd\index{RxFuncAdd}, or indirectly using SysLoadFuncs\index{SysLoadFuncs}.
One difference between Regina and OS/2
Rexx is that Regina requires that the case of the function name passed
to RxFuncAdd match the case of the function name in the shared library (which
is always lower-case in RegUtil). The effect of this is that existing
code which looks like this
\begin{verbatim}
call rxfuncadd 'SysFileTree', 'RexxUtil', 'SysFileTree'
\end{verbatim}
will fail, and should be re-written like this
\begin{verbatim}
call rxfuncadd 'sysfiletree', 'rexxutil', 'sysfiletree'
\end{verbatim}

Also note that Regina includes two executables, one called `rexx', and
the other called `regina'. The difference is that `rexx' includes the Rexx
interpreter as part of the executable, while `regina' loads the interpreter
from a shared library. RxFuncAdd works only with the `regina' version of
the interpreter (the `rexx' version is slightly faster, though).

\subsection{Licencing}

Regutil is distributed free of charge in the hopes that it will be
useful, but without any warranty. Previous versions of the library have
been distributed under the terms of the GNU Library General Public
License. This version is distributed under the terms of the Mozilla
Public License. The precise details of the licence are found in the file
MPL-1.0.txt in the distribution.

If you use the library purely as distributed by me, then you can
cheerfully ignore the licencing change. If you modify the source code or
adopt portions of it in your own programs or libraries, you should be
aware of and fulfill your obligations under the licence. I believe that
the restrictions placed by the Mozilla licence are less onerous than the
ones in the GNU Library licence, and they are more in the spirit in
which I would like my work to be distributed.

Although there are no obligations or restrictions related to use of the
library, I would prefer that you do not use regutil in applications
which cause injury or hardship to others. Also, if you derive a
significant monetary benefit from the use of regutil, please share a
portion with someone less fortunate. For instance, if you save \$10,000
by implementing an application with Regina and regutil, rather than
buying a commercial Rexx interpreter, you could give \$1,000 to Unicef.

\goodbreak

{\samepage
\section{Housekeeping Routines}

These are routines which help you use the other routines.

\subsection{SysLoadFuncs}

\begin{verbatim}
sysloadfuncs() -> 0
\end{verbatim}

SysLoadFuncs\index{SysLoadFuncs} registers all the other routines in the utility package
with the Rexx interpreter. This registration takes less work on your part than
registration using rxfuncadd, and it's probably faster to use
sysloadfuncs whenever you need more than one utility function, plus
it's less typing.

}

\subsection{SysDropFuncs}

\begin{verbatim}
sysdropfuncs() -> 0
\end{verbatim}

SysDropFuncs\index{SysDropFuncs} removes the registration of all the utilities in the package
from the Rexx interpreter. I don't feel there's a compelling reason for
doing this, and it has the potential to be positively harmful in the
IBM\index{IBM} interpreters, since they don't do proper reference counting for
load/drop. It's safe to call SysDropFuncs even if you didn't load all
the functions using SysLoadFuncs\index{SysLoadFuncs}. 

\section{File System Routines}

The file system routines manipulate files and directories in useful ways.

\subsection{List of File System Routines}

\begin{enumerate}

\item[SysCopyObject](from,to) {\rarrow} 0 or failure: copies a file
\item[SysCreateShadow](from,to) {\rarrow} 0 or failure: creates a link to a file
\item[SysFileDelete](file) {\rarrow} 0 or failure: deletes a file
\item[SysFileSearch](target,file,stem, [options]) {\rarrow} 0 or failure:
searches a file for some text
\item[SysFileSystemType](file) {\rarrow} string: returns the name of the
file-system in use for file
\item[SysFileTree](filespec,stem, [options], [tattrib], nattrib]) {\rarrow} 0 or failure: search
for files matching filespec
\item[SysMkDir](directory) {\rarrow} 0 or failure: creates a new directory
\item[SysMoveObject](from,to) {\rarrow} 0 or failure: renames a file
\item[SysRmDir](directory) {\rarrow} 0 or failure: removes a directory
\item[SysSearchPath](var,file) {\rarrow} full filename:  searches a list of
directories from an environment variable for a file
\item[SysTempFileName](template, [filter]) {\rarrow} name: returns a temporary
name based on a template;
\item[SysGetFileDateTime](name[, which]) {\rarrow} timestamp: returns a
timestamp for a file;
\item[SysSetFileDateTime](name[, date[, time]]) {\rarrow} 0 or failure: sets
the modification timestamp for a file;
\end{enumerate}

\subsection{Example}

Here's a script which creates a directory with a temporary name,
finds the file rgb.txt somewhere on the system, searches it for all
different kinds of blue, and writes them out to another temporary file
in the temporary directory.
\index{SysLoadFuncs}
\index{SysTempFileName}
\index{SysMkDir}
\index{SysFileTree}
\index{SysFileSearch}

\begin{verbatim}
 call rxfuncadd 'sysloadfuncs', 'rexxutil', 'sysloadfuncs'
 call sysloadfuncs

 /* make a temporary directory */
 dir = SysTempFileName('dir?????')
 call SysMkDir dir

 /* find an rgb.txt out there somewhere */
 if SysFileTree('/rgb.txt', 'RGB.', 'SO') = 0 & rgb.0 > 0 then do
   if SysFileSearch('blue', rgb.1, 'BLUE.') = 0 then do
     file = SysTempFileName(dir'/blue?????')
     do i = 1 to blue.0
       call lineout file,blue.i
       end
     end
   end
  
  exit 0
\end{verbatim}


\subsection{SysCopyObject}

\begin{verbatim}
SysCopyObject(from,to) -> 0 or failure
\end{verbatim}

Copies\index{SysCopyObject} the file named by {\it from} to a new name {\it to}.
The access and modification times are preserved, for file systems
that maintain that sort of arcane information.
Under OS/2, this file will also copy workplace shell objects.
Obviously, that doesn't work on other systems. \rcmsg={Returns 0
on success. See SysFileDelete\index{SysFileDelete}, section
\ref{sec:deleteobject},
for the meanings of the non-zero
failure codes.}\the\rcmsg

\subsection{SysCreateShadow}

\begin{verbatim}
SysCreateShadow(from,to) -> 0 or failure
\end{verbatim}

Under Unix, SysCreateShadow\index{SysCreateShadow} creates a link to the {\it from}
file, under the name {\it to}. If possible, this is a hard
link, but a symbolic link is made if necessary ({\it e.g.}, if 
the {\it from} and {\it to} directories are on different devices).
Note that the symbolic link will not work correctly unless the
{\it from} file is specified as a full path, so it's best
to specify full paths if the potential to cross devices exists.

Under NT, I intend\index{compatibility} for SysCreateShadow to create
short-cuts. Currently, to create a short-cut, you can use my other
package, w32funcs\index{W32 Funcs}.

\the\rcmsg

\subsection{SysFileDelete}

\begin{verbatim}
SysFileDelete(file) -> 0 or failure
\end{verbatim}

\label{sec:deleteobject}\index{SysFileDelete}Deletes the file specified by {\it file}. Returns\index{return codes} 0 on success.
On failure, it returns 1 (unknown cause of failure),
2 (no such file), 3 (path to file does not exist), 5 (insufficient
rights), 32 (file in use by another process), 36 (too many
symbolic links on the way to the file), 87 (invalid file name),
and 206 (file name is too long).

\subsection{SysFileSearch}

\begin{verbatim}
SysFileSearch(target,file,stem, [options]) -> 0 or failure
\end{verbatim}

\index{SysFileSearch}Searches the file {\it file} for the text in {\it target}, and puts
the matching lines in {\it stem}. {\it Stem.0} receives a count of
the lines, and lines are indexed sequentially starting with {\it stem.1}.
By default, the search is case-insensitive, however it can be made
case sensitive by specifying the option `c'. The other option `n'
causes each output line to have the line number in {\it file} to be
prepended to it.

The function returns 0 on success. On failure, it returns 2
(insufficient memory) or 3 (could not open {\it file} for reading).


\subsection{SysFileSystemType}

\begin{verbatim}
SysFileSystemType(file) -> string
\end{verbatim}

\index{SysFileSystemType}Returns the file system type used for the specified file.
For NT, this
should be just the drive letter and a colon, although it may be a
full path to a file (I believe this is an enhancement\index{compatibility} over
IBM's\index{IBM}
implementation, so be careful). For Unix, it should be the full path
to the file of interest.

On success, returns the file system name if it could be determined (or
`UFS' if it couldn't be), or the empty string if the drive or mount
point is not accessible.

\subsection{SysFileTree}

\begin{verbatim}
SysFileTree(filespec,stem, [options], [tattrib],
            [nattrib]) -> 0 or failure
\end{verbatim}

\index{SysFileTree}Finds all files whose names match {\it filespec}, and writes their
names
into {\it stem}.  {\it filespec} may contain wild-card characters such as
are normally allowed on the platform in question. On NT, I believe this
limits you to `*', which matches 0 or more occurances of any character,
and ?, which matches exactly one occurance of any character. On Unix,
the glob() routine, which usually follows the rules of /bin/sh, is
used. This allows character classes ([a-e] matches any letter from a to~e,
for instance), and probably other features which don't come to mind.
If {\it filespec} ends with a directory separator character (slash on Unix,
back-slash or slash on NT), the routine acts as if the pattern had
ended with `*'.

{\it options} controls how directories are searched, and how the output
is delivered.  By default, the output is the time-stamp, size, file
attributes, and full path to the file, for every file and directory
which matches {\it filespec}.  If {\it options} includes an `f', only
files are reported.  If it includes a `d', only directories are
reported.  If it contains `b', both files and directories are reported.
If more than one of these is given, the right-most one wins.  If {\it
options} contains `s', SysFileTree searches sub-directories for files
matching {\it filespec}.  If it includes `o', only the full path to the
file is reported.  If it includes `t' time-stamp is returned in the
format yyyy/mm/dd/hh/mi\index{compatibility}.
Note that IBM's\index{IBM} implementation uses
2-digit years. If {\it options} includes `l', the time-stamp is returned
in the format yyyy-mm-dd hh:mi:ss, which can be processed with the Rexx date()
and time() functions.

On Unix\index{compatibility} systems, the attributes are returned in the
usual format from
ls -l: the first byte is `-' for a normal file or `d' for a directory,
and it is followed by three `rwx' pairs indicating the read, write,
and execute permissions for each of the user, group, and others. On
NT, the attributes are ADHRS, matching the archive, directory, hidden,
read-only, and system bits.

{\it tattrib} allows the user to specify the
file attributes which should be matched. For each position in ADHRS,
`*' means match regardless of the state of the bit, `+' means to match if
it's set, and `-' means to match if it's not set. Thus `*-*+*' would
match all non-directories with the read-only bit set.
For Unix systems, the DOS attribute positions are preserved, but
they're given meanings which are specific to this implementation:

\begin{tabular}{lll}
\it Attribute&\it `+' match&\it `-' match\\
A&files with more than one hard link&files with exactly one hard link;\\
D&files with execute permission&files without execute permission;\\
H&files without read permission&files with read permission;\\
R&files without write permission&files with write permission;\\
S&files with owner id less than (`system' files)&files with owner greater
than or equal to 10.
\end{tabular}

In IBM's implementation, {\it nattrib}
uses the same scheme to specify how these attributes should be changed
by this function (which otherwise has no effect on its environment).
{\it nattrib} is not supported by this
implementation.\index{compatibility}

\subsection{SysMkDir}

\begin{verbatim}
SysMkDir(directory) -> 0 or failure
\end{verbatim}

\index{SysMkDir}Creates a sub-directory with the specified name. On Unix systems,
this is created with the permissions rwxr-xr-x, masked with the
value of the process's umask.

On success, returns 0.  On failure, it returns 1 (unknown cause of
failure), 2 (no such file), 3 (path to file does not exist), 5
(insufficient rights, quota exceeded, or the directory already exists),
36 (too many symbolic links on the way to the file), 87 (invalid file
name), 108 (file system is read-only), and 206 (file name is too long).


\subsection{SysMoveObject}

\begin{verbatim}
SysMoveObject(from,to) -> 0 or failure
\end{verbatim}

SysMoveObject\index{SysMoveObject} renames the file {\it from} to {\it to}. If these
files are on different devices, the file is copied and then the
original file is deleted, otherwise only the diretory entries are
manipulated.

Under OS/2, this function will also move workplace shell objects.
Obviously, that doesn't\index{compatibility} work on other systems. \the\rcmsg


\subsection{SysRmDir}

\begin{verbatim}
SysRmDir(directory) -> 0 or failure
\end{verbatim}

\index{SysRmDir}Removes the sub-directory with the specified name.

On success, returns 0.  On failure, it returns 1 (unknown cause of
failure), 2 (no such file), 3 (path to file does not exist), 5
(insufficient rights, quota exceeded, or the directory already exists),
16 (some other process is using the directory),
36 (too many symbolic links on the way to the file), 87 (invalid file
name), 108 (file system is read-only), and 206 (file name is too long).

\subsection{SysSearchPath}

\begin{verbatim}
SysSearchPath(path,file) -> full filename
\end{verbatim}

\index{SysSearchPath}Searches the list of directories specified by {\it path} for the file
specified by {\it file}. Each element of the path is separated by
the usual path separator for the platform\index{compatibility} ({\it e.g.}, `:' on Unix and
`;' on NT). The full file name must be specified (that is, `regina.exe'
rather than just `regina').

On success, returns the full path to the file. On failure, returns the
empty string.

\subsection{SysTempFileName}

\begin{verbatim}
SysTempFileName(template, [filter]) -> name
\end{verbatim}

\index{SysTempFileName}Given a prototype filename {\it template}, with up to five wild-card
characters, return a the name of a file which does not already exist,
replacing the wild-card characters with numbers. By default, the
wild-card characters is the question mark (?), but it can be any
character specified by {\it filter}.

The routine works by first generating a pseudo-random number and using
Digits from this number to replace the wild-card characters, and then
incrementing the number until there's no file matching the name
generated from the template.

\subsection{SysGetFileDateTime}

\begin{verbatim}
SysGetFileDateTime(name [, which]) -> timestamp
\end{verbatim}

SysGetFileDateTime\index{SysGetFileDateTime} returns a time-stamp
associated with the file identified by {\it name}.
The timestamp is returned in the format `yyyy-mm-dd hh:mi:ss'.

If {\it which} is `modify', the time of the last modification is
returned. If it's `access', the time of last access is returned.
If it's `create', the file creation time is returned. Only the first
letter of each of those options is significant. If the file system
doesn't support access and creation times, the function returns the
last modification time for everything.

\subsection{SysSetFileDateTime}

\begin{verbatim}
SysSetFileDateTime(name [, date [, time]]) -> success
\end{verbatim}

SysSetFileDateTime\index{SysSetFileDateTime} sets the last modification
time of the file specified by {\it name} to the date and time specified
by {\it date} and {\it time}. The format of {\it date} is `yyyy-mm-dd',
and the format of {\it time} is `hh:mi:ss'.

If neither {\it date} nor {\it time} are specified, the last modification
time is set to the current time. If {\it date} is specified but {\it
time} is not, only the date is changed. If {\it time} is specified by
{\it date} is not, only the time is changed.

Returns 0 on success, or --1 on failure.

\section{System Routines}

The system routines return information about the operating system,
library, or active processes, or perform process-control operations.
This is the major area of incompleteness in the library\index{completeness}.

\subsection{List of System Routines}

\begin{enumerate}

\item[SysIni]([inifile],app,key,val,stem) {\rarrow} value: retrieve values from
.ini files;
\item[SysBootDrive]() {\rarrow} value: returns the drive from which NT was
booted, or the name of the Unix kernel file;
\item[SysUtilVersion]() {\rarrow} value: returns the regutil version;
\item[SysVersion]() {\rarrow} value: returns the operating system version;
\item[SysWinVer]() {\rarrow} value: returns the operating system version;
\item[SysOS2Ver]() {\rarrow} value: returns the operating system version;
\item[SysLinVer]() {\rarrow} value: returns the operating system version;
\item[SysVersion]() {\rarrow} value: returns the operating system version;
\item[SysUtilVersion]() {\rarrow} value: returns the version of this library;
\item[SysDriveInfo](drive) {\rarrow} returns the free space on the drive,
or the partition containing the argument;
\item[SysDriveMap]([drive],[opt]) {\rarrow} list: lists accessible drives;
\item[SysSetPriority](class,delta) {\rarrow} 0 or success: set the priority
of the current process;
\item[SysQueryProcess](thing) {\rarrow} 0 or success: get the process ID, or
some canned data;
\item[SysSleep](time) {\rarrow} 0 or success: block for the specified
period of time;
\item[SysSwitchSession](name) {\rarrow} 0 or success: brings a named
application to the foreground;
\item[SysSystemDirectory]() {\rarrow} value: returns the name of the
system directory;
\item[SysVolumeLabel](drive) {\rarrow} returns the label on a specified
drive;
\item[SysWaitNamedPipe](name,[timeout]) {\rarrow} 0 or failure:
waits on a named pipe.

\end{enumerate}


\subsection{SysIni}

\begin{verbatim}
SysIni([inifile],app,key[,val]) -> value
SysIni([inifile],app,'all:',stemname) -> value
SysIni([inifile],'all:',stemname) -> value
\end{verbatim}

\index{SysIni}Retrieves a value from a .ini file. This refers to Windows 3.1-style
.ini files. I originally planned to use this function to retrieve values
from the NT Registry as well, but I can't be bothered at this point.
To read
the registry, you can use my other package, w32funcs\index{W32 Funcs}.

{\it inifile} is the name of the .ini file. The default is `win.ini'.
If you don't specify a path, the .ini file is expected to be in the
system directory.

{\it app} is the name of a block of parameters in an .ini file.
The block names appear in brackets in the file. {\it key} is the
name of the parameter being retrieved or set. {\it val} is the value
to set the parameter to. {\it stemname} is the name of a stem variable into
which application or key names can be enumerated.

If {\it app} and {\it key} are specified, but {\it val} is not,
the current value of the specified key is returned.

If {\it val} is `delete:', the specified key is deleted. If {\it key}
is `delete:' or not specified, the entire block of parameters is deleted. Note
that if {\it key} is not specified, the `delete:' keyword is optional.
The entire block of parameters will be deleted. It's not me, it's IBM.

If {\it key} is `all:', the names of the keys in the block are returned
in {\it stemname}, following the numeric index convention\index{numeric
index convention}.  If {\it app} is `all:', the names of all the blocks
in the file are returned in {\it stemname}.

\subsection{SysBootDrive}

\begin{verbatim}
SysBootDrive() -> value
\end{verbatim}

\index{SysBootDrive}Under NT, SysBootDrive returns the letter of the drive from which the
system was booted ({\it e.g.}, `C:' if the system was booted from
drive c). This is mostly useful under OS/2 when you want to change the
correct config.sys file. Under Unix, SysBootDrive() will return the
name of the kernel from which the system was booted, or `C:' if it
isn't implemented.

\subsection{SysWinVer}

\begin{verbatim}
SysWinVer() -> value
\end{verbatim}

\index{SysWinVer}Returns the system id and version in the format `{\it id major.minor}'.
For NT, {\it id} is `Windows95' or `WindowsNT'. For Unix, it is
the value returned by the command `uname -s'.

\subsection{SysOS2Ver}

\begin{verbatim}
SysOS2Ver() -> value
\end{verbatim}

SysOS2Ver\index{SysOS2Ver} is a synonym for SysWinVer.  Lesson 1 in writing portable
APIs:  don't change the function names when you move from one platform
to another, the way IBM\index{IBM} did.

\subsection{SysLinVer}

\begin{verbatim}
SysLinVer() -> value
\end{verbatim}

SysLinVer\index{SysLinVer} is another synonym for SysWinVer.

\subsection{SysVersion}

\begin{verbatim}
SysVersion() -> value
\end{verbatim}

SysVersion\index{SysVersion} is yet another synonym for SysWinVer. (Lesson 1 learned, I suppose).

\subsection{SysUtilVersion}

\begin{verbatim}
SysUtilVersion() -> value
\end{verbatim}

SysUtilVersion\index{SysUtilVersion} returns the version number of the
regutil library. Because the library is not strictly compatible with
IBM's RexxUtil library, it does not return the same version numbers.
The value returned by SysUtilVersion is the major version number followed
by the minor version and release numbers, concatenated together. For
instance, for version 1.1.5, the return value is 1.15. For 1.1.10, the
return value would be 1.110.

\subsection{SysDriveInfo}

\begin{verbatim}
SysDriveInfo(drive) -> value
\end{verbatim}

\index{SysDriveInfo}Under NT, returns the free space on the specified drive in the
format `{\it drive free total label}'. {\it label} is the
label of the drive, if any.
{\it free} and {\it total} are the
number of bytes free, and the total number of bytes on the drive.
{\it drive} is the argument.

Under Unix\index{compatibility}, instead of drive, any file or directory name can be
specified, and the information for the file's partition will be
returned.  The {\it drive} returned is the volume's mount point, and the
{\it label} is the actual device name.

\subsection{SysDriveMap}

\begin{verbatim}
SysDriveMap([drive],[opt]) -> list
\end{verbatim}

This function is not implemented for Unix\index{completeness}.

Under NT, SysDriveMap\index{SysDriveMap} returns a list of accessible drives. Under Unix,
it returns a list of mounted partitions. The optional {\it drive}
argument specifies the first drive to consider under NT, but has
no effect on Unix.

{\it opt} can be one of the following values:

\begin{enumerate}
\item[USED]List all accessible drives or mount points;
\item[FREE]For NT, lists available drive letters (that is, if you
have only a C: drive, it will list all the letters from D: to Z:). Under
Unix, it does nothing;
\item[LOCAL]Lists only local files systems. Under NT, this means drives which
are actually on the local machine and use a standard file system;
\item[REMOTE]Under Unix, returns only NFS and Samba-mounted drives.
Under NT, returns LAN drives, and drives mounted using an installable
file system;
\item[REMOVABLE]Lists drives which are not fixed or network drives, such
as floppies and ZIP drives, but excluding CD-ROM drives;
\item[CDROM]Lists CD-ROM drives;
\item[RAMDISK]Lists ram disks.
\end{enumerate}

\subsection{SysSetPriority}

\begin{verbatim}
SysSetPriority(class,delta) -> success code
\end{verbatim}

\index{SysSetPriority}Sets the priority of the current process. Possible values for
{\it class} (NT only\index{compatibility}) are:

\begin{enumerate}
\item[0]Don't change priority class;
\item[1]Change class to idle;
\item[2]Change class to normal;
\item[3]Change class to `real time';
\item[4]Change class to `server'.
\end{enumerate}

Don't use any value other than 0 unless you know what you're doing.

{\it delta} can be any value between -31 and 31. 31 tries to increase
the priority as much as it can, and -31 tries to decrease the priority
as much as it can.

On success, SysSetPriority returns 0. On failure, it returns a return
code which I may document some day.

\subsection{SysQueryProcess}

\begin{verbatim}
SysQueryProcess(thing) -> data
\end{verbatim}

SysQueryProcess\index{SysQueryProcess} returns information based on its input:

\begin{enumerate}
\item[PID]process id;
\item[TID]thread id (currently always returns 0 on Unix);
\item[PPRIO]process priority (currently always returns NORMAL);
\item[TPRIO]thread priority (currently always returns NORMAL);
\item[PTIME]process time used;
\item[TTIME]thread time used (currently always returns process time
used);
\end{enumerate}

Currently\index{completeness}, only PID and PTIME give anything like useful information.
TID works for NT.

\subsection{SysSleep}

\begin{verbatim}
SysSleep(time) -> success code.
\end{verbatim}

SysSleep\index{SysSleep} blocks the current process for {\it time} seconds. Time may
be a fraction\index{compatibility} of a second ({\it e.g.}, .24 or 6.5), but note that
this is incompatible with IBM's original SysSleep. It is compatible
with the Object Rexx SysSleep, and it's useful.

Calling SysSleep is better than, say, looping on calls to time().
This is called `busy waiting':
\begin{verbatim}
 endtime = time('s')+2
 do while time('s') < endtime
   nop
   end
\end{verbatim}
and it's bad because it uses all kinds of CPU cycles simply testing
the current time. The equivalent code using SysSleep:
\begin{verbatim}
 call SysSleep 2
\end{verbatim}
has the same effect on the program, but doesn't use additional cycles
because the blocking is handled by the system scheduler, which is
constantly testing the current time anyway.

\subsection{SysSwitchSession}

\begin{verbatim}
SysSwitchSession(name) -> success code
\end{verbatim}

SysSwitchSession\index{SysSwitchSession} is supposed to bring the session
identified by {\it name} to the foreground. Under NT, where it is implemented,
{\it name} is the name on the title
bar. I'll tell you more about the Unix\index{compatibility} implementation when it's done.

This function is not implemented\index{completeness} on Unix.

\subsection{SysSystemDirectory}

\begin{verbatim}
SysSystemDirectory() -> value
\end{verbatim}

\index{SysSystemDirectory}Under NT, returns the name of the system directory, which is generally
WinNT on the boot drive. On Unix, it returns `/etc'.

\subsection{SysVolumeLabel}

\begin{verbatim}
SysVolumeLabel(drive) -> name
\end{verbatim}

\index{SysVolumeLabel}On NT, returns the label on a specified drive. On Unix, returns
the device file associated with the specified volume.

This function is not implemented\index{completeness} on Unix.

\subsection{SysWaitNamedPipe}

\begin{verbatim}
SysWaitNamedPipe(name [, timeout]) -> 0 or success
\end{verbatim}

Waits for the specified named pipe to become readable. The
named pipe name must have the format \verb"\\server\pipe\name" on NT,
where {\it server} is the name of a server machine (or~`.' for the local
machine), {\it pipe} is `pipe', and {\it name} is a name which doesn't
include any slashes or back-slashes.
On Unix, a named pipe is just a fifo and can have any name. {\it
timeout} is specified in milliseconds. --1 means there is no timeout.
0 and omitting the timeout value cause the operation to wait some
default period of time.

If there is data to read on the pipe, returns 0. If the operation times
out, returns 1460. Otherwise, it returns a system-defined error number.

\section{Macro-Space Manipulation Routines}

The macro-space manipulation routines allow a program to control the
macros available in the execution environment. Most usefully, they
allow external macros to be loaded in to the local macro address space,
and they allow collections of macros to be saved to, and loaded from,
a compact, binary format. This allows library functions to be stored
externally and loaded quickly, and it may allow proprietary code to
be shipped in a format which is not susceptible to casual inspection.

As of version 2.2, the necessary API is provided only as a set of `stub'
routines in Regina, so these routines are not yet functional\index{completeness}.
They are not included in pre-compiled versions of regutil, since this
would force people to upgrade to Regina 2.2. They can be included in a
build for use with a later version of Regina or with another interpreter,
by adding ``-DMACROSPACE'' to the CFLAGS line in the appropriate make
file.

\subsection{List of Macro-Space Manipulation Routines}

\begin{enumerate}
\item[SysAddRexxMacro](name, file, [order]) {\rarrow} 0 or failure : adds a macro;
\item[SysClearRexxMacroSpace]() {\rarrow} 0 or failure : clears all macros;
\item[SysDropRexxMacro](name) {\rarrow} 0 or failure : drops a macro;
\item[SysLoadRexxMacroSpace](file) {\rarrow} 0 or failure : initialises a macro-space from a
file;
\item[SysQueryRexxMacro](name) {\rarrow} `B', `A' or `' : determines whether a macro is
defined;
\item[SysReorderRexxMacro](name,order) {\rarrow} 0 or failure : moves the search order of a
macro;
\item[SysSaveRexxMacroSpace](file) {\rarrow} 0 or failure : saves a macro space to a file.
\end{enumerate}


\subsection{SysAddRexxMacro}

\begin{verbatim}
SysAddRexxMacro(name, file, [order]) -> 0 or failure
\end{verbatim}

\index{SysAddRexxMacro}Reads a macro called {\it name} from a file called {\it file}
and makes it available to the current program. If {\it order} is
specified and starts with `A', the macro name will be added to the end of the
macro space. Otherwise, it will be added to the beginning. See
SysReorderRexxMacro\ref{sec:macorder} for a discussion of what this means.

Macros loaded using SysAddRexxMacro have the useful characteristics of external
functions (they are stored in a separate file) but act like locally
defined procedures (they can access global stem variables, for instance).

Returns 0\index{return codes} on success. The other possible return codes from the macro-space
functions are\label{sec:macrc} 1 (not enough storage available), 2
(requested function not found), 3 (file extension required for save), 4
(macro functions exist), 5 (file I/O error in save/load), 6 (incorrect
format for load), 7 (requested cannot be found), 8 (invalid search order
position), and 9 (API not initialized).


\subsection{SysClearRexxMacroSpace}

\begin{verbatim}
SysClearRexxMacroSpace() -> 0 or failure
\end{verbatim}

\index{SysClearRexxMacroSpace}Clears all macros previously loaded using
SysAddRexxMacro\index{SysAddRexxMacro}
or SysLoad\-Rexx\-Macro\-Space\index{SysLoadRexxMacroSpace} from the macro space.

\rcmsg={Returns 0 on success. See SysAddRexxMacro, section \ref{sec:macrc}, for the other
possible return values.}\the\rcmsg

\subsection{SysDropRexxMacro}

\begin{verbatim}
SysDropRexxMacro(name) -> 0 or failure
\end{verbatim}

\index{SysDropRexxMacro}Drops the named macro fromt he macro space.
The macro must have previously been loaded using
SysAddRexxMacro\index{SysAddRexxMacro}
or SysLoadRexxMacroSpace\index{SysLoadRexxMacroSpace}.

\the\rcmsg

\subsection{SysLoadRexxMacroSpace}

\begin{verbatim}
SysLoadRexxMacroSpace(file) -> 0 or failure
\end{verbatim}

\index{SysLoadRexxMacroSpace}Loads all macros from the file {\it file},
which must have been saved using
SysSave\-Rexx\-Macro\-Space\index{SysSaveRexxMacroSpace}. It's not guaranteed
that macro space files will be compatible between releases of Regina. It
{\it is} guaranteed that they will not be compatible between different Rexx
implementations\index{compatibility}.

\the\rcmsg

\subsection{SysQueryRexxMacro}

\begin{verbatim}
SysQueryRexxMacro(name) -> 'A', 'B', or ''
\end{verbatim}

\index{SysQueryRexxMacro}Searches the macro space for a function called
{\it name}. If it finds it, it returns `A' if the macro was loaded using
load order `after' or `B' if it was loaded using load order `before'.
If it doesn't find it, returns the empty string.

\subsection{SysReorderRexxMacro}

\begin{verbatim}
SysReorderRexxMacro(name,order) -> 0 or failure
\end{verbatim}

\index{SysReorderRexxMacro}Changes the search order for macro {\it
name}. If\label{sec:macorder} {\it order} begins with `B' (`before'),
the function from the macro space will override any locally-defined
function of the same name. If it begins with `A' (`after'), any
locally-defined function will over-ride the version loaded into the
macro space.

\the\rcmsg

\subsection{SysSaveRexxMacroSpace}

\begin{verbatim}
SysSaveRexxMacroSpace(file) -> 0 or failure
\end{verbatim}

\index{SysSaveRexxMacroSpace}Saves all macros loaded using SysAddRexxMacro\index{SysAddRexxMacro}
or SysLoad\-Rexx\-Macro\-Space\index{SysLoadRexxMacroSpace} to a file called {\it file}.
The file name must include an extension.

\the\rcmsg

\section{Console I/O Routines}

The console I/O routines allow simple terminal-mode updates.  The Curses
library\index{RxCurses} gives more flexibility,
and will be more efficient over slow
connections.
Rexx/TK\index{Rexx/TK} is currently the best option for implementing
GUI interfaes.

I originally considered implementing these routines using
curses, but the value added would be slight (SysCurPos and
SysTextScreenRead are the only functions which would be fixed by this),
and the availability of the full curses package makes the effort
redundant.

\subsection{List of Console I/O Routines}

\begin{enumerate}
\item[SysCls]() : clears the screen;
\item[SysCurPos]([row],[column]) {\rarrow} row column: moves the cursor, and
returns its current position on the screen;
\item[SysCurState](state): makes the cursor visible or invisible;
\item[SysGetKey]([echo],[timeout]): retrieves a keystroke;
\item[SysTextScreenRead](row,column,len) {\rarrow} text: reads the screen;
\item[SysTextScreenSize]() {\rarrow} rows columns: gets the size of the screen;
\item[RxMessageBox](text, [title], [button], [icon]) {\rarrow} button
id: displays a message box and returns the button selected.
\end{enumerate}

\subsection{Example}

Here's a script which prints an X of screen positions on the screen,
then waits for a keypress.
\index{SysLoadFuncs}
\index{SysDropFuncs}
\index{SysCurState}
\index{SysCurPos}
\index{SysCls}
\index{SysTextScreenSize}
\index{SysGetKey}

\begin{verbatim}
call rxfuncadd 'sysloadfuncs', 'rexxutil', 'sysloadfuncs'
call sysloadfuncs

call syscurstate 'off'
call syscls

parse value systextscreensize() with rows cols

top=min(rows,cols)-1

do i = 1 to top
  call syscurpos i,i
  call charout 'stdout', '('i',' i')'
  call syscurpos i,top-i+1
  call charout 'stdout', '('i',' top-i+1')'
  end
call SysGetKey 'noecho'
call syscurstate 'on'
call SysDropFuncs
say ''
\end{verbatim}


\subsection{SysCls}

\begin{verbatim}
SysCls()
\end{verbatim}

SysCls\index{SysCls} clears the screen as quickly as possible.

\subsection{SysCurPos}

\begin{verbatim}
SysCurPos([row],[column]) -> row column
\end{verbatim}

SysCurPos\index{SysCurPos} sets the cursor position to {\it row} and {\it column}, and
returns the former position. If {\it row} and {\it column} are not
returned, it doesn't move the cursor. I don't know how to retrieve the
current position on Unix\index{compatibility}, so it always returns 0 0 on that platform. For
more advanced screen handling, consider using the RxCurses\index{RxCurses} package.

\subsection{SysCurState}

\begin{verbatim}
SysCurState(state)
\end{verbatim}

SysCurState\index{SysCurState} makes the cursor visible or invisible. If {\it state}
is `on', the cursor is made visible. If it is `off', the cursor
is made invisible.

\subsection{SysGetKey}

\begin{verbatim}
SysGetKey([echo],[timeout]) -> keystroke
\end{verbatim}

SysGetKey\index{SysGetKey} returns a keystroke. If {\it echo} is specified, and it is
`n' or `no', the keystroke is not displayed on the screen. Otherwise
it is.

If {\it timeout} is specified, it is a number of seconds to wait
for input. As with SysSleep, fractions of seconds are allowed.
if {\it timeout} seconds pass without a key being pressed, SysGetKey
returns the empty string.
By default, or if {\it timeout} is 0, SysGetKey waits until a key has
been pressed before returning. This behaviour is incompatible\index{compatibility}
with IBM's implementation.

For compatibility\index{compatibility} with IBM's\index{IBM} implementation,
function keys can be returned
in an ugly, system-dependent manner. For NT, this means that if SysGetKey
returns a 0, you must call it again, and the second return value tells
you what key was pressed. For Unix, it means something different again
-- generally, alt-keys will return either a high-ascii value, or escape
followed by the ascii value of the key, while function keys return
different escape sequences depending on the terminal.

The current release tries to return `f1' for F-1, `Home' for the home
key, and so forth. To figure out what gets returned, you have to
press the keys and print it out.

\subsection{SysTextScreenRead}

\begin{verbatim}
SysTextScreenRead(row,column,len) -> text
\end{verbatim}

SysTextScreenRead\index{SysTextScreenRead} returns the characters printed on the screen for {\it len}
characters, starting at position {\it row},{\it column}. The end of line
is indicated by a new-line character (ascii value 10).

SysTextScreenRead\index{completeness} is not implemented for Unix systems, because I don't
know how to retrieve the information from a tty terminal.

\subsection{SysTextScreenSize}

\begin{verbatim}
SysTextScreenSize() -> rows columns
\end{verbatim}

SysTextScreenSize\index{SysTextScreenSize} returns the number of rows and
columns in an NT text
window, or a Unix terminal.  For NT, the size is the size of the buffer
behind the window, so if you have a scroll-back set up, for instance, the
value will be larger than the actual screen size.  For Unix, the size is
the size the kernel believes the terminal to be.  This will generally be
accurate for xterms and many terminal emulators, but can be wrong if
you're using a terminal emulator which uses non-standard sizes, on a
system (HP-UX comes to mind) which doesn't account for that.  The
problem can be fixed by using the stty command to tell the system the
actual size of the window.

\subsection{RxMessageBox}

\begin{verbatim}
RxMessageBox(text, [title], [button], [icon]) -> button id.
\end{verbatim}

RxMessageBox\index{RxMessageBox} displays a message box on the screen
and waits for the user to press a button. It's not a console I/O
function, but it doesn't seem to fit in anywhere else, so I document
it here.

{\it Text} is the text that will be written in the message box.
The system will wrap long text at around 120 characters, or 60\% of the
screen width (this is from observation~-- I haven't seen any system
documentation on this). This tends to look ridiculous, so you can
force line breaks by adding a line-feed (character 10) to the string.
See the example for\dots an example.

{\it Title} is the text that is put on the title bar. By default, the
title is `Error!', meaning that you really should specify something.

{\it Icon} is one of `hand', `question', `exclamation', `asterisk',
`information', or `stop'; the default is `hand'.  Note that `hand' and
`stop' present the same icon, and on my machine, it's a sort-of X in a
red circle, which is nothing like a hand or a stop-sign. `Question' presents a
question mark in a bubble. ``Asterisk' and `information' present the
same icon, which is a lower-case i in a bubble, and exclamation is an
exclamation point in a yellow rhombus.

{\it Button} specifies which buttons appear on the message box. It is
one of `ok' for an OK button, `okcancel' for an OK button and a Cancel
button, `abortretryignore', for an abort button, a retry button, and an
ignore button, `yesnocancel' for a yes button, a no button and a cancel
button, `yesno' for a yes button and a no button, and `retrycancel' for
a retry button and a cancel button.

The return code is a number from 1 to 7 indicating which button was
selected by the user. The numbers correspond to `OK', `Cancel', `Abort',
`Retry', `Ignore', `Yes', or `No', respectively.

\begin{verbatim}
rcc = RxMessageBox('Things are going badly, which is ' ||,
                   'my fault, but your problem.' || d2c(10) ||,
                   'Press cancel to give up, or retry to take ' ||,
                   'another stab at it.', 'Oops', 'RetryCancel')

/* cancel */
if rcc = 2 then do
  say 'good choice'
  exit 1
  end
else do
  say 'your funeral'
  redo()
  end
\end{verbatim}


\section{Stem Manipulation Routines}

The stem manipulation routines are used to manipulate stem variables.
Not all of the options in IBM's routines are supported, and regutil
has a few extra functions which are not available in IBM's version.

Generally speaking, the stems must follow the numeric index convention\index{numeric index convention}.
This is a long-standing way of emulating numeric arrays in Rexx, where
the .0 stem element holds the number of entries in the array ({\it count}), and
elements 1 through {\it count} hold the data.

I include sysdumpvariables() here even though it's not specifically anything
to do with stems.

\subsection{List of Stem Manipulation Routines}

\begin{enumerate}
\item[SysDumpVariables]([filename]) {\rarrow} 0 or -1: dump the names and values of all
variables to a file;
\item[SysStemCopy](from, to[, fromindex, toindex, count, insertoverlay]) {\rarrow} 0 or -1: copy
a stem to another stem;
\item[SysStemDelete](stem, index[, count]) {\rarrow} 0 or -1: delete elements from a stem;
\item[SysStemInsert](stem, index, value) {\rarrow} 0 or -1: insert a value into a stem;
\item[SysStemSort](stemname[, order] [,sensitivity] [,startpos,endpos] [,firstcol,lastcol]) {\rarrow} 0 or -1:
sort the elements of a stem;
\item[RegStemDoOver](stem, variable[, outstem]) {\rarrow} 0 or 1:
enumerates the indexes of a stem;
\item[RegStemRead](filename, stemname) {\rarrow} 0 or 1: read file
into stem;
\item[RegStemWrite](filename, stemname) {\rarrow} 0 or 1: write file
from stem;
\item[RegStemSearch](needle, haystack[, start] [, flags]) {\rarrow} 0 or index:
search a stem for a value.
\end{enumerate}

\subsection{Example}

Here's a script which reads a file into a stem, sorts the stem, and then writes
it out to the file again:
\index{SysLoadFuncs}
\index{RegStemRead}
\index{SysStemSort}
\index{RegStemWrite}

\begin{verbatim}
call rxfuncadd 'sysloadfuncs', 'rexxutil', 'sysloadfuncs'
call sysloadfuncs

call regstemread 'bob', 'bob'
call sysstemsort 'bob'
call regstemwrite 'bob', 'bob'
\end{verbatim}


\subsection{SysDumpVariables}

\begin{verbatim}
SysDumpVariables([filename])
\end{verbatim}

SysDumpVariables\index{SysDumpVariables} is a debugging aid which dumps all variables to the
file {\it filename} in the format
\begin{verbatim}
Name=GREETING, Value="Have a nice day."
\end{verbatim}

Nothing special is done with variables that include new-lines or quotes.
If no file is specified, the dump is written to standard output.


\subsection{SysStemCopy}

\begin{verbatim}
SysStemCopy(from, to[, fromindex, toindex, count, insertoverlay])
\end{verbatim}

SysStemCopy\index{SysStemCopy} copies stem {\it from} to {\it to}. The stems must currently
follow the numeric index convention (this might change in the future).

{\it fromindex} is the index number of the first element in {\it from} which
should be copied. {\it toindex} is the index number of the first target
element in {\it to}. The default for both indices is 1.
{\it count} is the number of elements to copy. The default is all of
them. If {\it insertoverlay} is `I', the elements from {\it from} are
inserted into {\it to}, and existing elements in {\it to} are shifted.
Otherwise, existing elements in {\it to} are overwritten.

If {\it toindex} is beyond the end of {\it to}, the array is
extended and filled with zero-length strings. If {\it fromindex}+{\it
count} is greater than the number of elements in {\it from}, only the
number of elements between {\it fromindex} and the end of {\it from} are
copied.

If the default options are given for {\it fromindex}, {\it toindex},
{\it count}, and {\it insertoverlay}, {\it from} is copied exactly on
top of {\it to}. So, if {\it to} has 20 elements, and {\it from} has
10 elements, the last 10 elements of {\it to} will be deleted.
Probably, this is a bug\index{compatibility}, but you can work around
it by passing {\it count} as {\it from}.0.

\subsection{SysStemDelete}

\begin{verbatim}
SysStemDelete(stem, index[, count]) -> 0 or -1
\end{verbatim}

\index{SysStemDelete}Deletes {\it count} entries from a stem, starting at index {\it index}.
The default count is 1.
The stem must follow the numeric index convention.

\subsection{SysStemInsert}

\begin{verbatim}
SysStemInsert(stem, index, value)
\end{verbatim}

\index{SysStemInsert}Inserts {\it value} at index position {\it index}. If there are elements
with larger indices than {\it index}, they are shifted up one.
The stem must follow the numeric index convention.

\subsection{SysStemSort}

\begin{verbatim}
SysStemSort(stem[, order] [, sensitivity] [,startpos, endpos]
[,firstcol,lastcol])
\end{verbatim}

SysStemSort\index{SysStemSort} sorts a stem. This is a pure ASCII sort, which doesn't take into account
any language-based collation sequence\index{compatibility}.
{\it order} can be `ascending' or `descending', the default is
`ascending'. {\it sensitivity} can be `sensitive' or `insensitive', which determines
whether to fold upper-case letters into lower-case letters. Again, this doesn't
take into account accented characters, although it might if Regina were to call
setlocale(3).  Only the first letter of each
of these options is significant.

If {\it startpos} and {\it endpos} are given, only elements from {\it
startpos} to {\it endpos} (inclusive) will be sorted.

If {\it firstcol} and {\it lastcol} are given, elements will be sorted
based on the {\it firstcol\/}th to {\it lastcol\/}th characters, inclusive.
We start counting characters at 1.

The stem must follow the numeric index convention.

\subsection{RegStemDoOver}

\begin{verbatim}
RegStemDoOver(stem, variablename[, outstem]) -> 0 or 1
\end{verbatim}

RegStemDoOver\index{RegStemDoOver} simulates the object rexx construct `do x over y.'.
It allows the indices of a stem to be treated as data by retrieving
each index in turn. It returns 1 while there are additional elements,
and 0 after the last element has been returned.

{\it stem} is the name of the stem. {\it variablename} is the name of a
variable to set to the next stem index. If given, {\it outstem} is the
name of a stem to set to the complete set of indices of {\it stem},
using the numeric index convention.

\begin{verbatim}
/* read values into a stem */
do until name = 'end'
  parse linein name otherstuff
  data.name = otherstuff
  end

/* process the values */
do while regstemdoover('data.', 'i')
   /* skip the `end' element. This is something
    * to do with this dumb example, not a feature
    * of regstemdoover */
   if i \= 'end' then
     call somefunction i, data.i
   end
\end{verbatim}

The stem does {\it not} have to follow the numeric index convention (otherwise
the function would be a bit pointless, but I thought I'd mention it).
You can't nest calls to RegStemDoOver. For instance, this code will not
work as desired:

\begin{verbatim}
/* loop over indices of data */
do while regstemdoover('data.', 'i')
   /* and now loop over mana */
   do while regstemdoover('mana.', 'j'
     call somefunction i, j
     end
   end
\end{verbatim}

Instead, you must first store the indices of `data' in another stem.

Also, RegStemDoOver does not pick up changes which have occurred to the
stem since the first call to the function.

\subsection{RegStemRead}

\begin{verbatim}
RegStemRead(filename, stem)
\end{verbatim}

RegStemRead\index{RegStemRead} reads the contents of file {\it filename} into stem stem
using the numeric index convention (number of lines in the 0 element,
data in numbered elements starting at 1).
When possible, it uses memory-mapped I/O to read the values, which
should be the most efficient method possible. As a result, RegStemRead
is expected to be measurably faster than, eg, using linein, as well as
being more convenient.

\subsection{RegStemWrite}

\begin{verbatim}
RegStemWrite(filename, stem)
\end{verbatim}

RegStemWrite\index{RegStemWrite} reads the contents of stem {\it stem} to file {\it filename}.
The stem must follow the numeric index convention.
This might be faster than using lineout, and it's convenient, but it's mostly
included as a companion to RegStemRead\index{RegStemRead}.

\subsection{RegStemSearch}

\begin{verbatim}
RegStemSearch(needle, haystack [, start] [,flags]) -> 0 or index
\end{verbatim}

RegStemSearch\index{RegStemSearch} searches the stem {\it haystack} for
{\it needle}.
It returns the index position of a stem element which matches {\it
needle}, or 0 if there are no such elements.
The stem must follow the numeric index convention.

{\it Start} is the starting index position (the default is 1). {\it
Flags} can be any combination of `C', `E', and `S'. `C' indicates that
the search should be case-sensitive (the default is case-insensitive).
`E' indicates that an exact match is required (the default is to
perform a substring match). `S' indicates that the stem is sorted.
When the stem is sorted, RegStemSearch uses a binary search, otherwise
it uses a linear search.

RegStemSearch is primarily a convenience function. In its fastest
mode of operation (performing exact matches on a case-sensitively
sorted stem), the overhead of looking up Rexx variable values makes
it slightly slower than the equivalent code written in Rexx, and much
slower than a more sensible use of stems. What I mean by this is that
this code:

\begin{verbatim}
colours.0 = 3
colours.1 = 'blue'
colours.2 = 'green'
colours.3 = 'red'

if regstemsearch(colour, 'colours',,'ces') \= 0 then
   say colour 'is a colour'
\end{verbatim}

\noindent would be more sensible and also much faster as

\begin{verbatim}
colours. = 0
x = 'blue'
colours.x = 1
x = 'green'
colours.x = 1
x = 'red'
colours.x = 1

if colours.colour then
   say colour 'is a colour'
\end{verbatim}

In its default mode of operation, it can be used along with RegStemRead
to replace SysFileSearch, but again the overhead of setting and
retrieving Rexx variables from the library makes it slower.


\section{Semaphore Routines}

A semaphore is an inter-process communications mechanism which allows
information to be signalled between processes.
Generally speaking, semaphores are counters which can be shared between
processes, and which  allow processes to block while waiting for the semaphore
to reach special values (normally 0 and not-0).

RexxUtil provides two specialised kinds of semaphores: mutual exclusion,
or mutex semaphores, and event semaphores.

You use mutex semaphores to cooperatively control access to shared
resources. For instance, if two programs use the same log file to
record their progress, they might use a mutex to ensure that log
messages don't overlap. The routine that writes to the log would
first `lock' the mutex by calling SysRequestMutexSem\index{SysRequestMutexSem}, then
write the log message, flush the log file, and finally release
the semaphore using SysReleaseMutexSem\index{SysReleaseMutexSem}.

An event semaphore allows a process to wait efficiently until another
process lets it know that there's something to do. For instance,
a server process which accepts requests in the form of text files
could call SysWaitEventSem\index{SysWaitEventSem} when it has nothing to do.
A client process which has created input for the server would call
SysPulseEventSem\index{SysPulseEventSem} to notify the server that an new file has
been written.

There are two kinds of event semaphores. Manual-reset semaphores have
their states changed to `posted' or `reset' and the state stays that way
no matter how many other processes wait for the semaphore. Auto-reset semaphores
(the default) automatically change from `posted' to `reset' as soon as a
waiting process has been released. A manual-reset semaphore is a bit
like a door which is always either open or shut, while an auto-reset is
like a turnstile that lets one person through, then locks.
See SysPulseEventSem and SysPostEventSem for more details.

\subsection{List of Semaphore Routines}

\begin{enumerate}
\item[SysCloseEventSem](semid) {\rarrow} 0 or failure: close an event
semaphore;
\item[SysCloseMutexSem](semid) {\rarrow} 0 or failure: close an mutex
semaphore;
\item[SysCreateEventSem]([name],[manualreset]) {\rarrow} handle:
create an event semaphore;
\item[SysCreateMutexSem]([name]) {\rarrow} handle:
create a mutex semaphore;
\item[SysOpenEventSem](name) {\rarrow} handle:
open an event semaphore;
\item[SysOpenMutexSem](name) {\rarrow} handle:
open a mutex semaphore;
\item[SysPostEventSem](semid) {\rarrow} 0 or failure:
set the semaphore status to `on';
\item[SysPulseEventSem](semid) {\rarrow} 0 or failure:
set the semaphore status to `on' then `off' again;
\item[SysReleaseMutexSem](semid) {\rarrow} 0 or failure:
unlock a mutex semaphore;
\item[SysRequestMutexSem](semid, [timeout]) {\rarrow} 0 or failure:
lock a mutex semaphore;
\item[SysResetEventSem](semid) {\rarrow} 0 or failure:
set the semaphore status to `off';
\item[SysWaitEventSem](semid, [timeout]) {\rarrow} 0 or failure:
wait for an event semaphore to be turned `on'.
\end{enumerate}

\subsection{SysCloseEventSem}

\begin{verbatim}
SysCloseEventSem(semid) -> 0 or failure
\end{verbatim}

\index{SysCloseEventSem}Closes the event semaphore associated with {\it semid}.
{\it semid} must have been returned by SysOpenEventSem\index{SysOpenEventSem} or
SysCreateEventSem\index{SysCreateEventSem}. A return code of 0 means success. Any other return
code means `not success'.

\subsection{SysCloseMutexSem}

\begin{verbatim}
SysCloseMutexSem(semid) -> 0 or failure
\end{verbatim}

\index{SysCloseMutexSem}Closes the mutex semaphore associated with {\it semid}.
{\it semid} must have been returned by SysOpenMutexSem\index{SysOpenMutexSem} or
SysCreateMutexSem\index{SysCreateMutexSem}. A return code of 0 means success. Any other return
code means `not success'.

\subsection{SysCreateEventSem}

\begin{verbatim}
SysCreateEventSem([name],[manualreset]) -> handle
\end{verbatim}

\index{SysCreateEventSem}Creates a new event semaphore keyed on {\it name}.  If {\it name} is not
specified, the semaphore is private to the process, and so completely
useless until Regina supports multi-threading.  If {\it manualreset}
is set to a non-zero value, it changes the behaviour of SysPulseEventSem and
SysPostEventSem as described later.

On success, SysCreateEventSem returns a handle to the semaphore, which
should be used in subsequent semaphore calls.  On failure, it returns
the empty string.

\subsection{SysCreateMutexSem}

\begin{verbatim}
SysCreateMutexSem([name]) -> handle
\end{verbatim}

\index{SysCreateMutexSem}Creates a new mutex semaphore keyed on {\it name}.  If {\it name} is not
specified, the semaphore is private to the process, and so completely
useless until Regina supports multi-threading.  I hope you're not
getting the impression this documentation has been cut-and-pasted a lot.

On success, SysCreateMutexSem returns a handle to the semaphore, which
should be used in subsequent semaphore calls.  On failure, it returns
the empty string.

\subsection{SysOpenEventSem}

\begin{verbatim}
SysOpenEventSem(name) -> 0 or handle
\end{verbatim}

\index{SysOpenEventSem}Opens an event semaphore keyed on {\it name}. The semaphore must
have been previously created (usually by another process) using
SysCreateEventSem\index{SysCreateEventSem}.

On success, SysOpenEventSem returns a handle to the semaphore, which
should be used in subsequent semaphore calls.  On failure, it returns
0. I don't know why this is different from SysCreateEventSem.

\subsection{SysOpenMutexSem}

\begin{verbatim}
SysOpenMutexSem(name) -> 0 or handle
\end{verbatim}

Opens a mutex semaphore keyed on {\it name}.  The semaphore must
have been previously created (usually by another process) using
SysCreateMutexSem\index{SysCreateMutexSem}.

On success, SysOpenMutexSem returns a handle to the semaphore, which
should be used in subsequent semaphore calls.  On failure, it returns
0.

\subsection{SysPostEventSem}

\begin{verbatim}
SysPostEventSem(semid) -> 0 or failure
\end{verbatim}

Sets an event semaphore to `posted' state.

If the semaphore
is auto-reset (meaning the {\it manualreset} flag was {\it not} set
in SysCreateEventSem\index{SysCreateEventSem}), the behaviour is
different when there are processes waiting than it is when there are no
processes waiting.
If there are waiting processes, they are all released, and the state of the
semaphore is set to `reset'. If there are no waiting processes, the
state of the semaphore is set to `posted'.

If the semaphore is manual-reset, it stays in `posted' state until it is
explicitly reset using SysPulseEventSem\index{SysPulseEventSem} or
SysResetEventSem\index{SysResetEventSem}.

\subsection{SysPulseEventSem}

\begin{verbatim}
SysPulseEventSem(semid) -> 0 or failure
\end{verbatim}

Sets an event semaphore to `posted' and then automatically resets it.

If there are no processes waiting on the semaphore, the semaphore is
reset without releasing anything.

Otherwise, if the semaphore is auto-reset, exactly one process will be
released before the semaphore is reset. If the semaphore is manual-reset,
all waiting processes will be released before the semaphore is reset.
Hopefully, this table will make the behaviour clear:

\begin{tabular}{lllll}
\it Type&\it Event&\it Waiters&\it Final State&\it Empty State\\
Auto-reset&Pulse&Release 1&Reset&Reset\\
&Post&Release all&Reset&Posted\\
&Reset&None&Reset&Reset\\
Manual-reset&Pulse&Release all&Reset&Reset\\
&Post&Release all&Posted&Posted\\
&Reset&None&Reset&Reset\\
\end{tabular}

\subsection{SysReleaseMutexSem}

\begin{verbatim}
SysReleaseMutexSem(semid) -> 0 or failure
\end{verbatim}

\index{SysReleaseMutexSem}Unlocks a mutex semaphore which was previously locked using
SysRequestMutexSem\index{SysRequestMutexSem}.

\subsection{SysRequestMutexSem}

\begin{verbatim}
SysRequestMutexSem(semid[, timeout]) -> 0 or failure
\end{verbatim}

\index{SysRequestMutexSem}Locks a mutex semaphore. If the semaphore is already locked by
another process, waits {\it timeout} milliseconds. If {\it timeout}
is not specified, it will wait until the end of time (which is currently
projected to be in September 2038).

If it returns 0, then the
lock was attained.  If it returns a non-zero value, then the lock was
not attained, and the shared resource must not be manipulated.
The return value on time-out is supposed to be 121, but this sounds
quite improbably to me.

You should always release the mutex by calling
SysReleaseMutexSem\index{SysReleaseMutexSem} as soon as possible after
aquiring it.


\subsection{SysResetEventSem}

\begin{verbatim}
SysResetEventSem(semid) -> 0 or failure
\end{verbatim}

\index{SysResetEventSem}Sets an event semaphore to `reset'. See SysPulseEventSem and SysPostEventSem
for more discussion.

\subsection{SysWaitEventSem}

\begin{verbatim}
SysWaitEventSem(semid[,timeout]) -> 0 or failure
\end{verbatim}

Waits for an event semaphore to be set to `posted'.  If {\it timeout} is
specified, SysWaitEventSem waits up to {\it timeout} milliseconds.
Otherwise, it waits forever.

If the semaphore is auto-reset and its state is `posted' before the call
to SysWaitEventSem, the state will be changed to `reset'.

SysWaitEventSem returns 0 when it is returning due to the semaphore
being posted. It's supposed to return 121, if you can believe it,
if the function timed out. Other non-zero return codes can't be good.

\clearpage % or \cleardoublepage
\phantomsection % fixes the link anchor
\addcontentsline{toc}{section}{\indexname}
\printindex


\end{document}

