When talking about a "file" in the REXX language, the more ambiguous terminology "stream" is substituted for "file". This is because REXX functions such as STREAM(), CHAROUT(), etc, do not distinguish between reading/writing to files on a permanent media such as a hard drive (ie, what we call "persistent streams"), and reading/writing to devices that don't permanently store their data such as the console (window) or serial port or some pipes (ie, what we call "transient streams"). In other words, you can use CHAROUT() to write characters to both a console window as well as a file on disk. With the former, the characters are simply displayed, but otherwise not stored. With the latter, the operating system actually stores the characters to a permanent file. The net result is that you can go back and reread the data you wrote out in the latter case, but not the former case. This distinction is important to us because sometimes we have to disallow certain operations for transient streams, such as "seeking" to various "stream positions". Also, for transient streams, we may have to wait for incoming data, whereas with persistent streams, we don't.

Included at the end of this page are more examples of file I/O.

The following functions operate upon streams:

CHARIN Reads in one or more characters.
CHAROUT Writes out one or more characters.
CHARS Counts the number of characters waiting to be read.
CHDIR Change the current directory.
COPYFILE Copies (duplicates) one or more files.
DELETEFILE Deletes one or more files.
DIR Create or delete a directory.
DIRECTORY Query the current directory, and/or change the directory.
DRIVEINFO Queries information about a drive such as its free space.
DRIVEMAP Queries the drives by type, such as listing all CDROM drives.
EDITNAME Transforms a filename based upon a template containing wildcards.
FILESPEC Extracts part of a pathname.
LINEIN Reads in a line.
LINEOUT Writes out a line.
LINES Counts the number of lines waiting to be read.
LOADTEXT Reads all of the lines of a text file into a stem variable.
MATCHNAME Tests for the existence of a certain file or directory, perhaps with certain attributes. Alternately, enumerate all of the files in a given directory, perhaps filtering only those that match a certain template containing wildcards, or which have certain attributes.
MOVEFILE Moves one or more files from one location to another. When the file remains on the same drive, this essentially renames a file.
PATH Gets a full pathname from a filename, queries the current directory, sets the current directory, and/or splits a pathname into separate elements.
QUALIFY Gets a full pathname from a filename.
SEARCHPATH Locates a file, or queries path environment variables, or returns the path to special directories such as Windows.
STATE Tests if a file/stream actually exists.
STREAM Opens/closes/seeks streams, and reports stream diagnostics/information.
VALUEIN Reads in a numeric value from a binary (ie, non-text) file.
VALUEOUT Write out numeric values to a binary (ie, non-text) file (ie, in non-text format).


CHARIN

Reads in one or more characters.

Synopsis
chars = CHARIN(stream, position, length)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to read from STDIN (typically, get one or more characters from the user via a prompt in the console window).

position specifies at what character position (within the stream) to start reading from, where 1 means to start reading at the very first character in the stream. If omitted, the default is to resume reading at where a previous call to CHARIN() or VALUEIN() left off (or where you set the "read character pointer" via STREAM's SEEK).

length indicates the requested number of characters to read in. If 0, then CHARIN() merely sets the "read character pointer" to position without reading any characters and returns an empty string. (ie, Similiar to using STREAM's SEEK). If length is omitted, CHARIN() defaults to reading only 1 character.

If both position and length are omitted, some REXX interpreters will close the stream. (ie, Similiar to using STREAM's CLOSE).

Returns

A string containing the characters. This may be less than the number of characters requested if there are not enough remaining characters in the stream, including even an empty string if there are no more characters remaining at all, or there was an error. See the notes below.

Notes

You may use the CHARS function to determine how many remaining characters are available to be read, before calling CHARIN().

If the operating system has a problem reading from the stream, then this raises a NOTREADY condition, and CHARIN() may return less characters than requested (or even none).

After a call to CHARIN(), you can use STREAM's 'D' option to return an informative error message as to the nature of any error that may have occurred. This will return an empty string if there was no error. Otherwise, unless you SIGNAL ON NOTREADY, it may be difficult to distinguish between an error occuring, or reaching the end of a persistent stream.

If a NOTREADY condition is raised, your NOTREADY handler can use CONDITION('D') to return the name of the stream in error (and then use STREAM's 'D' option to fetch an informative error message).

For a transient stream (such as STDIN):

You cannot specify a position, or this raises a SYNTAX condition with ANSI error of 40.42.

If there are not as many characters available as how many you have requested, then program execution may stop until the requested number of characters are available. Execution will resume when the requested characters are finally made available (or the user aborts via CTRL-C which will raise a HALT condition).

For a persistent stream:

If position is beyond the last character in the stream, then this raises a NOTREADY condition, and CHARIN() will return an empty string.

If there are not as many characters available as the number requested, then the remaining characters (and only those characters) are returned immediately. A NOTREADY condition is not raised. A subsequent call to CHARIN() (without specifying a new position), after you have already read all characters from the stream, will then raise a NOTREADY condition, and CHARIN() will return an empty string.

Examples

Example use
Return value
CHARIN(, , 1)
/* Gets the next keypress from the user */
CHARIN('myfile', , 10)
/* Reads the next 10 bytes from 'myfile' */
CHARIN('myfile', 1)
/* Resets the read character pointer to the start of 'myfile' */

See also

LINEIN, VALUEIN, CHARS


CHAROUT

Writes out one or more characters.

Synopsis
result = CHAROUT(stream, string, position)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to write to STDOUT (typically, display the data in the console window).

position specifies at what character position (within the stream) to start writing the data, where 1 means to start writing at the very first character in the stream. If omitted, the default is to resume writing at where a previous call to CHAROUT() or VALUEOUT() left off (or where the "write character pointer" was set via STREAM's SEEK).

string are the characters (ie, data) to write out. If omitted or an empty string, then CHAROUT() merely sets the "write character pointer" to position without writing any characters. (ie, Similiar to using STREAM's SEEK).

If both position and string are omitted, some REXX interpreters will close the stream. (ie, Similiar to using STREAM's CLOSE).

Returns

0 if the string was written out successfully. If an error, CHAROUT() returns a count of how many characters remain unwritten.

Notes

If the operating system has a problem writing to the stream, then this raises a NOTREADY condition, and CHAROUT() may return non-zero.

After a call to CHAROUT(), you can use STREAM's 'D' option to return an informative error message as to the nature of any error that may have occurred. This will return an empty string if there was no error.

Program execution will stop until all requested data has been written to the stream (or the user aborts via CTRL-C which will cause a HALT error).

If a NOTREADY condition is raised, your NOTREADY handler can use CONDITION('D') to return the name of the stream in error (and then use STREAM's 'D' option to fetch an informative error message).

For a transient stream (such as STDIN):

You cannot specify a position, or this raises a SYNTAX condition with ANSI error of 40.42.

For a persistent stream:

If position is beyond the immediate end of the stream (ie, more than one character beyond the last character already in the stream), then this raises a NOTREADY condition and CHAROUT() returns non-zero.

Examples

Example use
Return value
CHAROUT(, 'Hi')
/* Prints "Hi" to the console */
CHAROUT('myfile', 'Hi')
/* Writes 2 chars of "Hi" to 'myfile' */
CHAROUT('myfile')
/* Closes 'myfile' */

See also

LINEOUT, VALUEOUT


CHARS

Counts the number of characters waiting to be read from a particular stream (via CHARIN(), or perhaps LINEIN()).

Synopsis
howmany = CHARS(stream)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to count how many characters are available from STDIN (typically, check if the user has already typed one or more characters via a prompt in the console window).

Returns

A count of how many characters are waiting to be read. or 0 if none.

Notes

If there are no characters waiting to be read, then CHARS() always returns 0. But if there are characters waiting to be read, on some interpreters, CHARS() may return the actual number of such characters. On other interpreters, only a 1 will ever be returned to indicate that "there is at least one character waiting to be read". So, you should not assume that CHARS() returns an accurate count of just how many characters are waiting to be read.

Examples

Example use
Return value
CHARS()
/* Counts how many chars the user has already typed */
CHARS('myfile')
/* Counts the remaining chars in 'myfile' */

See also

CHARIN, LINEIN, VALUEIN


CHDIR

Changes the current directory.

Synopsis
result = CHDIR(dirname)

Args

dirname is the directory to make current. This could be a relative path (ie, referenced from the current directory) rather than a full path (ie, referenced from the root of a drive).

Returns

1 if success, or 0 if an error.

Notes

How the directory is specified may be platform dependent.

If an error in setting the directory to dirname, then Reginald's RXFUNCERRMSG() can be used to retrieve an informative error message as to the nature of the failure. Unlike DIRECTORY(), a SYNTAX condition will not be raised.

To query the current directory, use PATH() or DIRECTORY().

Not all interpreters support this function.

Examples

Example use
Return value
CHDIR('C:\Blort')
'1' /* if success */

See also

PATH, DIRECTORY, DIR, FILESPEC, MATCHNAME


COPYFILE

Copies one or more files.

Synopsis
result = COPYFILE(source, destination, option)

Args

source is the name of the file to copy. This may contain the full path (ie, drive and directory names also) or just the filename part (in which case the source file is assumed to be in the current directory). The filename part may contain the wildcard characters * and ? to copy all files matching that template, or no wildcards if copying a specific file/directory with that name. If omitted, source defaults to "*.*" (ie, all files in the current directory are copied). To copy all files in a specific directory other than the current directory, source must be the name of that directory and end with a slash or backslash character. The directory must exist, or an error will be returned.

destination is the new name for the destination (ie, copy). This may contain the full path (ie, drive and directory names also) or just the filename part (in which case the destination is copied to the current directory). The filename part may contain the wildcard characters * and ? to transform the source filename as per EDITNAME, or no wildcards if a specific name is desired. To copy all source files into another specific directory other than the current directory but retain the same names, then destination must be the name of that directory and end with a slash or backslash character. The directory must exist, or an error will be returned.

option must be the following:

Value
Meaning
'R' (Replace) Overwrite any destination file that has the same name. Without this option, COPYFILE() will return an error if there is already a destination file with the same name.

Returns

An empty string if success, or an error message if an error.

Notes

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names.

COPYFILE() will return an error if you specify a specific file to copy and it doesn't exist. COPYFILE() will not return an error if you specify some wildcard template for source, but there are no files that match.

This is a Reginald-specific function. Other interpreters may not support it.

Examples

Example use
Return value
COPYFILE('C:\Blort', 'D:\Blort2')
/* Copies 'C:\Blort' to 'D:\Blort2' */
COPYFILE('C:\Blort', 'D:\Blort2', 'R')
/* Copies 'C:\Blort' to 'D:\Blort2', overwriting D:\Blort2 if it already exists */
COPYFILE('C:\MyDir\', 'C:\MyDir2\')
/* Copies all files in 'C:\MyDir' to 'C:\MyDir2' */
COPYFILE('C:\*.bak', 'C:\MyDir\')
/* Copies all files in C:\ that end with .bak to 'C:\MyDir' */
COPYFILE('*.bat', '*.bak')
/* Copies all files in the current directory that end with .bat, renaming them with a .bak extension 

See also

MOVEFILE


DELETEFILE

Deletes one or more files.

Synopsis
result = DELETEFILE(name)

Args

name is the name of the file to delete. This may contain the full path (ie, drive and directory names also) or just the filename part (in which case the source file is assumed to be in the current directory). The filename part may contain the wildcard characters * and ? to delete all files matching that template, or no wildcards if deleting a specific file/directory with that name. If omitted, name defaults to "*.*" (ie, all files in the current directory are deleted). To delete all files in a specific directory other than the current directory, name must be the name of that directory and end with a slash or backslash character. The directory must exist, or an error will be returned.

Returns

An empty string if success, or an error message if an error.

Notes

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names.

DELETEFILE() will not return an error if the file doesn't exist.

This is a Reginald-specific function. Other interpreters may not support it.

Examples

Example use
Return value
DELETEFILE('C:\Blort')
/* Deletes 'C:\Blort' */
DELETEFILE('C:\MyDir\')
/* Deletes all files in 'C:\MyDir' */
DELETEFILE('*.bak')
/* Deletes all files in the current directory that end with .bat */

See also

MOVEFILE


DIR

Create or delete a directory.

Synopsis
error = DIR(dirname, operation)

Args

dirname is the name of the directory to create or delete. This could be a relative path (ie, referenced from the current directory) rather than a full path (ie, referenced from the root of a drive).

operation must be one of the following:

Value
Meaning
'C' Create the directory.
'D' Delete the directory.

If omitted, operation defaults to 'C'.

Returns

An empty string if success, or an error message if an error.

Notes

How the directory is specified may be platform dependent.

DIR() does not return an error if the directory that you are trying to create already exists. On the other hand, if the directory that you're trying to create conflicts with an existing filename in the same parent directory, then this is an error.

If creating a directory, and any parent directories do not exist, they will also be created. For example, if you pass a dirname of C:\temp\mydir\mysubdir, and although C:\temp exists, there is no mydir inside of it, then mydir will be automatically created along with mysubdir. When deleting a directory, parent directories are not deleted.

dirname may end with a slash or backslash.

DIR() is a Reginald-specific function. Other interpreters may not support it.

Examples

Example use
Return value
DIR('C:\MyDir') /* Creates C:\MyDir */
'' /* if successful */
DIR('C:\MyDir', 'D') /* Deletes C:\MyDir */
'' /* if successful */

See also

CHDIR, DIRECTORY, FILESPEC, QUALIFY


DIRECTORY

Query the current directory, and/or change the directory.

Synopsis
current = DIRECTORY(dirname)

Args

dirname is the directory to make current. This could be a relative path (ie, referenced from the current directory) rather than a full path (ie, referenced from the root of a drive). If omitted, then the directory is not changed.

Returns

The full pathname of the current directory.

Notes

How the directory is specified may be platform dependent.

If an error occurs in setting the directory to dirname, then Reginald raises a SYNTAX error, and your SYNTAX handler can use CONDITION('D') to return an informative error message about the problem. So too, a SYNTAX error is raised if there is a problem returning the current directory's name.

Not all interpreters support this function.

Examples

Example use
Return value
DIRECTORY()
'C:\Windows' /* whatever the current dir is */
DIRECTORY('Blort') /* Assume we're in C:\MyDir */
'C:\MyDir\Blort'

See also

PATH, CHDIR


DRIVEINFO

Queries information about a drive such as its free space.

Synopsis
error = DRIVEINFO(varname, drive)

Args

drive is the name of the drive whose information is to be returned, for example 'C' for the C drive. If omitted, then information is returned for the current drive.

varname is the name of the REXX variable where information is returned. The name of the drive itself is returned in varname (so if drive is omitted, you can find out what the current drive is). The returned drive name always ends with a colon and backslash. The Free Bytes is returned in the variable name with a .0 extension. The Drive Size is returned in the variable name with a .1 extension. The Volume Serial Number is returned in the variable with a .2 extension. The Volume Label is returned in the variable name with a .3 extension. The file system name (ie, "FAT", "NTFS", etc) is returned in the variable with a .5 extension. The length of a filename component is returned in the variable with a .6 extension. (If the drive supports long file names, this will be greater than 11). The drive type is returned in the variable with a .4 extension. (See DRIVEMAP() for the types. Attributes for this drive are returned in the variable with a .7 extension.

The attribute bits for a drive are:

Bit
Meaning
0 Case of filenames is preserved when saved.
1 Case matters in filenames.
2 Unicode is preserved in filenames when saved.
3 The file system preserves and enforces ACLs on this drive.
4 Files may be compressed individually.
15 The entire drive is compressed, for example, with Doublespace or Drivespace.

Returns

"0" if success, or an error number if a failure.

Notes

An appropriate error message can be gotten by passing the returned error number to UNIXERROR. The error number and message may be operating system specific.

The drive name may be specified with a colon and or a trailing backslash, and may even be the full path name of a file or directory upon the drive.

Not all interpreters support this function.

Examples

Example use
Return value
DRIVEINFO('Info')
/* Returns info about the current drive in the variable named Info */
DRIVEINFO('Blort', 'C')
/* Returns info about the C drive in the variable named Blort */
DRIVEINFO('Blort', 'C:\windows')
/* Returns info about the C drive in the variable named Blort */

See also

DRIVEMAP, PATH


DRIVEMAP

Queries the drives by type, such as listing all CDROM drives.

Synopsis
listing = DRIVEMAP(start, type)

Args

start is the drive at which to start listing drives. For example, 'C' skips the 'A' and 'B' drives, and starts listing at the 'C' drive. If omitted, then the first drive listed is 'A'.

type is what type of drives to list. It may be one of the following:

Type
Meaning
'CDROM' List only CDROM drives.
'FIXED' List only FIXED drives (ie, drives without removeable media, such as a hard drive).
'REMOVEABLE' List only drives with removeable media.
'MEMORY' List only RAM drives.
'NETWORK' List only network drives.

If type is omitted, then all of the above types of drives are listed.

Returns

If successful, a string containing all of the drives (of the specified Type) is returned, each separated by a space. For example, 'A:\ B:\ C:\'. If an error (or no drives of that Type are found), an empty string is returned.

Notes

The start drive name may be specified with a colon and or a trailing backslash, and may even be the full path name of a file or directory upon the drive.

Not all interpreters support this function.

Examples

Example use
Return value
DRIVEMAP()
/* Lists all drives */
DRIVEMAP('C', 'CDROM')
/* Lists all CDROM drives, skipping A and B drives */

See also

DRIVEINFO, PATH


EDITNAME

Transforms a filename based upon a template containing wildcards.

Synopsis
newname = EDITNAME(name, template, options)

Args

name is the filename to which the template is applied. This could contain the full path (ie, drive and directory names too) or just the filename part. If a full path is specified, you'll have to specify the 'U' or 'S' option.

When name is a drive or directory name (rather than a file's name), you should end name with a \ character (unless your intention is to transform the name of a directory in order to create a new directory name).

template is the template to apply to the filename. This could contain the full path or just the filename part. If a full path is specified, you'll have to specify the 'U', 'S', and/or 'T' option. Characters in the template replace their respective characters at the same positions in name, except for the wildcard characters ? and *. ? is replaced by the one, respective character in name at the same position. * is replaced by the respective character in name at the same position followed by all other characters up to a dot. Also, you can choose to have any drive and directory names on the template replace the drive and directory names on name.

If template is omitted, it defaults to *.* (ie, the transformed name has the same filename and extension parts as the Source, although the drive and directory may be different if you specify the 'S' option).

When template is a directory's name (as opposed to a file), you must end the arg with a \ character, or \*.* (unless name is also a directory name, and you wish to transform it as so).

option must be the following:

Value
Meaning
'U' Use the drive/directory names on name, and ignore any drive/directory names on template.
'S' Use the drive/directory names on template, unless the 'T' option is also specified, and ignore any drive/directory names on name.
'T' Ignore any drive/directory names on template.

If omitted, operation defaults to none of the above. (ie, Drive and directory names are utilized upon both name and template. The drive/directory names of template are appended to the drive/directory names of name. You should therefore first strip off any undesired drive/directory names before calling EDITNAME).

Returns

The new filename with the template applied to name.

Notes

EDITNAME() can be used to easily transform the filename part of a full pathname, for example to change the name of a file so that you can use the new name to create another file without overwriting the original. Or, it can be used to strip off the drive and directory on the original name and put a different drive and directory on the name.

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names, and will substitute the proper character (on newname) for the given operating system.

The original name is not altered.

This is Reginald-specific. Other interpreters may not support this function.

Examples

Example use
Return value
EDITNAME('hello', 'hi')
'hi'
EDITNAME('hello.cmd', '*.exe')
'hello.exe'
EDITNAME('hello.cmd', 'hi.*')
'hi.cmd'
EDITNAME('hello.cmd', '*.*')
'hello.cmd'
EDITNAME('C:\mydir\hello.cmd', 'c:\', 'S')
'c:\hello.cmd'
EDITNAME('C:\mydir\hello.bak', '*.bak', 'U')
'C:\mydir\hello.bak'
EDITNAME('c:\mydir\', 'd:\mydir2\hi.bak', 'U')
'c:\mydir\hi.bak'
EDITNAME('mydir\mydir2\hello.cmd', 'c:\*2.*', 'S')
'c:\hello2.cmd'
EDITNAME('C:\mydir\hello.cmd', 'c:\', 'ST')
'hello.cmd'

See also

PATH, MATCHNAME, FILESPEC, QUALIFY


FILESPEC

Extracts part of a pathname.

Synopsis
part = FILESPEC(option, pathname)

Args

pathname is the full path name of the file/stream, complete with drive and directory names, as well as any possible extension upon the file's name. For example, "C:\WINDOWS\NOTEPAD.EXE" includes all four elements -- the drive name "C:", the directory names "\WINDOWS\", the filename "NOTEPAD.EXE", and the extension ".EXE".

option indicates which part of the full path you wish to be returned, as so:

Option
Meaning
D Return the drive name.
P Return the directory names.
N Return the file name (including extension).
E Return the extension only.

Returns

The requested part of the path if success, or an empty string if no such part exists in pathname.

Notes

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names.

Not all interpreters support this function.

Examples

Example use
Return value
FILESPEC('P', 'C:\MyDir\MySubDir\Blort.txt')
'\MyDir\MySubDir\'
FILESPEC('D', 'C:\MyDir\MySubDir\Blort.txt')
'C:'
FILESPEC('N', 'C:\MyDir\MySubDir\Blort.txt')
'Blort.txt'
FILESPEC('E', 'C:\MyDir\MySubDir\Blort.txt')
'.txt'

See also

PATH, QUALIFY


LINEIN

Reads in a line from a particular stream.

Synopsis
line = LINEIN(stream, position, count)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to read from STDIN (typically, get a line from the user via a prompt in the console window).

position specifies at what line position (within the stream) to start reading from, where 1 means to start reading at the very first line in the stream. If omitted, the default is to resume reading at where a previous call to LINEIN() left off (or where you set the "read line pointer" via STREAM's SEEK).

count indicates the requested number of lines to read in. If specified, count can be only 1 or 0. If 0, then LINEIN() merely sets the "read line pointer" to position without reading any line. (ie, Similiar to using STREAM's SEEK), and returns an empty string. If count is 1 or omitted, LINEIN() reads 1 line.

If both position and count are omitted, some REXX interpreters will close the stream. (ie, Similiar to using STREAM's CLOSE).

Returns

A string containing the characters of one line. Any operating-system-specific "end of line" characters are stripped from the end of the line. A blank line will return an empty string, but also an error will cause an empty line to be returned. See the notes below.

Notes

You may use the LINES function to determine how many remaining lines are available to be read, before calling LINEIN().

If the operating system has a problem reading from the stream, then this raises a NOTREADY condition, and LINEIN() will return an empty string.

After a call to LINEIN(), you can use STREAM's 'D' option to return an informative error message as to the nature of any error that may have occurred. This will return an empty string if there was no error. Otherwise, unless you SIGNAL ON NOTREADY, it may be difficult to distinguish between an error occuring, or encountering a blank line, or reaching the end of a persistent stream.

If a NOTREADY condition is raised, your NOTREADY handler can use CONDITION('D') to return the name of the stream in error (and then use STREAM's 'D' option to fetch an informative error message).

Intermingling calls to CHARIN() and LINEIN() upon the same stream can result in odd behavior unless you specify position on a call to LINEIN() after calling CHARIN() (and vice versa).

For a transient stream (such as STDIN):

You cannot specify a position, or this raises a SYNTAX condition with ANSI error of 40.42.

If there is not a line available, then program execution may stop until a line is available. Execution will resume when the line is finally made available (or the user aborts via CTRL-C which will raise a HALT condition).

For a persistent stream:

If position is beyond the last line in the stream, then this raises a NOTREADY condition, and LINEIN() will return an empty string.

A subsequent call to LINEIN() (without specifying a new position), after you have already read all lines from the stream, will raise a NOTREADY condition, and LINEIN() will return an empty string.

Examples

Example use
Return value
LINEIN(, , 1)
/* Gets the next line from the user */
CHARIN('myfile', , 1)
/* Reads the next line from 'myfile' */
CHARIN('myfile', 1)
/* Resets the read line pointer to the start of 'myfile' */

See also

CHARIN


LINEOUT

Writes out a line to a particular stream.

Synopsis
result = LINEOUT(stream, string, position)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to write to STDOUT (typically, display the data in the console window).

position specifies at what line position (within the stream) to start writing the line, where 1 means to start writing at the very first line in the stream. If omitted, the default is to resume writing at where a previous call to LINEOUT() left off (or where the "write line pointer" was set via STREAM's SEEK).

string are the characters (ie, data) to write out as one complete line. (Any necessary, operating-system-specific "end of line" characters are automatically added to the end of the line). If omitted or an empty string, then LINEOUT() merely sets the "write line pointer" to position without writing any line. (ie, Similiar to using STREAM's SEEK).

If both position and string are omitted, some REXX interpreters will close the stream. (ie, Similiar to using STREAM's CLOSE).

Returns

0 if successful. If an error, the number of lines unwritten (ie, 1).

Notes

Normally, if you set position to something other than the end of the stream (ie, one line past the last line already in the stream), then all characters/lines after that position in the original stream are deleted. The net result is that you truncate the stream at that position (ie, you change where the end of the stream occurs), and then append your new line at this new end point.

If you would prefer to be able to overwrite certain data within the middle of a stream, without destroying all original data after that point, then you can use Reginald's 'OPTIONS NOLINEOUTTRUNC'.

If the operating system has a problem writing to the stream, then this raises a NOTREADY condition, and LINEOUT() may return non-zero.

After a call to LINEOUT(), you can use STREAM's 'D' option to return an informative error message as to the nature of any error that may have occurred. This will return an empty string if there was no error.

Program execution will stop until the line has been written to the stream (or the user aborts via CTRL-C which will cause a HALT error).

If a NOTREADY condition is raised, your NOTREADY handler can use CONDITION('D') to return the name of the stream in error (and then use STREAM's 'D' option to fetch an informative error message).

Intermingling calls to CHAROUT() and LINEOUT() upon the same stream can result in odd behavior unless you specify position on a call to LINEOUT() after calling CHAROUT() (and vice versa).

For a transient stream (such as STDIN):

You cannot specify a position, or this raises a SYNTAX condition with ANSI error of 40.42.

For a persistent stream:

If position is beyond the immediate end of the stream (ie, more than one line beyond the last line already in the stream), then this raises a NOTREADY condition, and LINEOUT() returns non-zero.

Examples

Example use
Return value
LINEOUT(, 'Hi')
/* Prints "Hi" to the console and moves to the next line */
LINEOUT('myfile', 'Hi')
/* Writes a line containing "Hi" to 'myfile' */
LINEOUT('myfile')
/* Closes 'myfile' */

See also

CHAROUT


LINES

Counts the number of lines waiting to be read from a particular stream (via LINEIN()).

Synopsis
howmany = LINES(stream, mode)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to count how many lines are available from STDIN (typically, check if the user has already typed one or more lines via a prompt in the console window).

mode is one of the following:

Mode
Meaning
'C' (Count) Count how many more lines are actually waiting to be read.
'N' (Normal) Return a 1 if there are one or more lines to be read, or a 0 if there are no more.

If mode is omitted, then the default mode is used. (Usually, this is 'Normal, but some interpreters allow you to set the default mode. See notes below).

Returns

A count of how many lines are waiting to be read. or 0 if none.

Notes

On some interpreters, the LINES() built-in function may have two different "modes" of operation.

When LINES() is used in the 'Normal' mode, then it always returns a 1 if there is at least one more line to be read in the file. Even if there is more than one line yet to be read, it will still return a 1.

There is another mode that LINES() supports. In 'Count' mode, LINES() actually does count how many more lines are actually in the file. (So, if you have just opened the file, and not yet read anything from it, then you will be at the beginning of the file, and LINES() will report how many lines are really in the file). 'Count' mode involves a lot more overhead than 'Normal' mode, so that's why there is a 'Normal' mode. Sometimes, it's important to a programmer to know only if there is another line to be read, but not necessarily how many more. So, 'Normal' mode is a lot quicker for that purpose.

If there are no lines waiting to be read, then LINES() always returns 0 in either mode.

Reginald allows setting the default mode of LINES(). Use an 'OPTIONS NOFAST_LINES_BIF_DEFAULT' statement once prior to any calls to LINES() to set the default mode as 'Count'. To set the default mode as 'Normal', then use 'OPTIONS FAST_LINES_BIF_DEFAULT'.

Examples

Example use
Return value
LINES()
/* Counts how many lines the user has already typed */
LINES('myfile')
/* Counts the remaining lines in 'myfile' */

See also

LINEIN


LOADTEXT

Reads all of the lines of a text file into successive tails of one stem variable.

Synopsis
result = LOADTEXT(stemname, stream, options)

Args

stemname is the name of the stem variable to store the lines of the text file. If omitted, the default is to get lines from STDIN (typically, from the user typing them via a prompt in the console window) until a blank line (ie, the ENTER key is pressed without any other characters before it).

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to read whatever lines are available from STDIN (typically, lines the user has already typed via a prompt in the console window).

options may be any or all of the following:

Options
Meaning
'T' (Trailing) Strip out trailing spaces from each line.
'L' (Leading) Strip out leading spaces from each line.
'B' (Blank) Strip out blank lines.

If option is omitted, it defaults to none of the above.

Returns

A 1 if successful. or 0 if an error.

Notes

The stem name, with a tail of 0 appended to it, will be a count of how many lines are in the text file. Each line will be in its own tail, where the stem name with a 1 appended contains the first line, the stem name with a 2 appended contains the second line, etc. For example, if you pass a stemname of 'mystem.', then mystem.0 contains a count of how many lines are read in, mystem.1 contains the first line, mystem.2 contains the second line, mystem.3 contains the third line, etc.

Note: You must put quotes around stemname if you're specifying it as a literal string. Otherwise, it will be considered to be a variable whose value is the name of the desired stem. Also, stemname must end with a dot. Note that a legal stem name could include several dots, such as mystem.firstfile. for the name.

If you have trapped the NOTREADY condition, then NOTREADY is raised if there is an error reading the lines of the file.

If the stream is already open (because you have used some other function to read from it), and the current read position is not at the beginning of the file, then LOADTEXT() will read only those lines from the current read position to the end of the file. To read from the beginning, use Stream()'s SEEK command to reposition the file, or the CLOSE command to close it, before calling LOADTEXT().

This is a Reginald proprietary built-in.

Examples

Example use
Return value
LOADTEXT('blort.', 'C:\WINDOWS\SYSTEM.INI')
/* Reads the lines of 'C:\WINDOWS\SYSTEM.INI' into a variable named blort. */
LOADTEXT('blort.', 'file.txt', 'TL')
/* Reads the lines of 'file.txt' into blort, stripping leading and trailing spaces on each line. */

See also

LINEIN, LINES


MATCHNAME

Tests for the existence of a certain file or directory, perhaps with certain attributes. Alternately, can enumerate all of the files in a given directory, perhaps filtering only those that match a certain template containing wildcards, or which have certain attributes.

Synopsis
next = MATCHNAME(search, stem, template, attributes, options)

Args

template is the template to match, if you wish to filter by name. This may contain the full path (ie, drive and directory names also) if searching a specific drive or directory for matching names, or just the filename part (to search the current directory for names that match). The filename part may contain the wildcard characters * and ? to match any file matching that template, or no wildcards if testing for the existence of a specific file/directory with that name. If omitted, template defaults to "*.*" (ie, searches the current directory for all files/directories without filtering by name).

attributes are the attributes to match, if you wish to filter by attributes. attributes can be any of the following:

Attribute
Meaning
'D' Include directories (but not sub-directories inside of directories).
'S' Include system files.
'N' Include normal files.
'H' Include hidden files.
'C' Include compressed files.
'R' Include read-only files.
'A' Include files with the archive bit set.
'T' Include temporary files.

If attributes is omitted, it defaults to none of the above (ie, items are not filtered by their attributes). More than one attribute may be specified. The order of attributes is irrelevant.

options determines what information is reported by MATCHFILE(). options can be any of the following:

Option
Meaning
'N' Report the name of the matching item.
'F' Fully qualify the matching item's name. (ie, Include the drive and directory names). Otherwise, only the filename part is reported.
'S' Report the size of the matching item. Directories will have an empty string as the size.
'D' Report the last modified date of the matching item.
'A' Report the attributes of the matching item.
'O' Perform one match only. It is not necessary to specifically close down the search if MATCHFILE() returns a matching item.

If options is omitted, it defaults to 'N'. More than one option may be specified. The order of options is irrelevant.

stem is the name of the variable where the above information is reported. If the item's name is to be reported, it is stored in the variable with the same name as stem. If the item's size is to be reported, it is stored in the variable name of stem with a tail name of .0 added. If the item's date is to be reported, it is stored in the variable name of stem with a tail name of .1 added. If the item's attributes are to be reported, they are stored in the variable name of stem with a tail name of .2 added. If stem is omitted, then this is an indication that you wish to abort a series of calls that you have been making to MATCHNAME() (ie, close down the search on this template).

search is the instance (ie, number) for this MATCHNAME() template. If you are going to be enumerating more than one template simultaneously (by intermixing calls to MATCHFILE() with different templates), then you need to give each template its own, unique search number. Otherwise, if you're enumerating only one template at a time, then you may omit search.

Returns

Each time that MATCHNAME() is successfully called, it returns an empty string, and sets your stem variable to information pertaining to the next item that matches your template and attributes. If an error, then MATCHNAME() closes down the search and returns an error message. If there are no more items that match your template and attributes, then MATCHFILE() closes down the search and returns the string DONE.

Notes

MATCHNAME() can be used to easily resolve a filename containing the wildcard characters * and ?. In this way, your script can support "filename global pattern matching", allowing the user to easily specify many files that your script must act upon, without forcing the user to type the name of every single file that he wants processed. (ie, He will instead specify a template that contains wildcard characters to be replaced using MATCHNAME()).

How the drive and directories are specified in template may be platform dependent. Reginald will accept either a slash or backslash to separate directory names. When reporting the name, PATH() will ensure that it is properly formatted for the given operating system. Reginald will also trim off any leading and trailing spaces from template upon operating systems where such spaces are not legal. The original template is not altered.

This is Reginald-specific. Other interpreters may not support this function.

Unless you specify the 'O' option, then you must either loop around calls to MATCHNAME() until it either returns an error message or the string DONE, or you must explicitly end the search by calling MATCHFILE() one last time and omit the stem arg. If you specify the 'O' arg, then you can't make repeated MATCHFILE() calls to enumerate all of the matches for a given template. You can make only one call to enumerate the first match.

Examples
/* Check if a sub-directory named 'MyDir' exists in
 * the current directory, and if so, return its full name.
 */
IF MATCHNAME(, 'Info', 'MyDir', 'DSHCAT', 'ONF') == "" THEN
   SAY "MyDir's full name is" Info
ELSE
   SAY "MyDir does not exist."
RETURN

/* Check if a file named 'MyFile' exists in the
 * current directory, and if so, return its full name.
 */
IF MATCHNAME(, 'Info', 'MyFile', 'NSHCAT', 'ONF') == "" THEN
   SAY "MyFile's full name is" Info
ELSE
   SAY "MyFile does not exist."
RETURN

/* Check if a hidden file named 'MyFile' exists in the
 * current directory, and if so, return its full name and size.
 */
IF MATCHNAME(, 'Info', 'MyFile', 'H', 'OSNF') == "" THEN DO
   SAY "MyFile's full name is" Info
   SAY "Size =" Info.0
END
ELSE
   SAY "MyFile does not exist."
RETURN

/* Check if a file named 'MyFile' exists in the
 * directory named C:\MyDir and get its last modified date.
 */
IF MATCHNAME(, 'Info', 'C:\MyDir\MyFile', 'NSHCAT', 'OS') == "" THEN
   SAY "MyFile exists. Date modified:" Info.1
ELSE
   SAY "MyFile does not exist."
RETURN

/* Enumerate all of the files that end in .bak in the
 * current directory, printing their names.
 */
DO UNTIL error \= ""

   /* Get next match. */
   error = MATCHNAME(, 'Info', '*.bak', 'NSHCAT')

   /* No error? Print the information. */
   IF error == "" THEN SAY Info

/* Continue if more, possible matches. */
END


/* Enumerate all of the files that end in .bak in the
 * C:\ directory until finding one named 'autoexec.bat'
 * and then abort the search at that point.
 */
DO UNTIL error \== ""

   /* Get next match. */
   error = MATCHNAME(, 'Info', 'C:\*.bak', 'NSHCAT')

   /* No error? Print the information. */
   IF error == "" && Info == 'autoexec.bat' THEN DO

      /* Abort the search. */
      CALL MATCHNAME()

      /* End the loop. */
      error = 'DONE'

   END

/* Continue if more, possible matches */
END
See also

PATH, FILESPEC, STATE


MOVEFILE

Moves one or more files from one location to another. When the file remains on the same drive, this essentially renames a file.

Synopsis
result = MOVEFILE(source, destination)

Args

source is the name of the file to move. This may contain the full path (ie, drive and directory names also) or just the filename part (in which case the source file should be in the current directory). The filename part may contain the wildcard characters * and ? to move all files matching that template, or no wildcards if moving a specific file/directory with that name. If omitted, source defaults to "*.*" (ie, all files in the current directory are moved). To move all files in a specific directory other than the current directory, source must be the name of that directory and end with a slash or backslash character. The directory must exist, or an error will be returned.

destination is the new name for the destination (ie, moved file). This may contain the full path (ie, drive and directory names also) or just the filename part (in which case the destination is just the source file renamed). The filename part may contain the wildcard characters * and ? to transform the source filename as per EDITNAME, or no wildcards if a specific name is desired. To move all source files into another specific directory other than the current directory but retain the same names, then destination must be the name of that directory and end with a slash or backslash character. The directory must exist, or an error will be returned.

Returns

An empty string if success, or an error message if an error.

Notes

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names.

MOVEFILE() will return an error if you specify a specific file to move and it doesn't exist. MOVEFILE() will not return an error if you specify some wildcard template for source, but there are no files that match. MOVEFILE() will return an error if there is already a destination file with the same name as destination.

This is a Reginald-specific function. Other interpreters may not support it.

Examples

Example use
Return value
MOVEFILE('C:\Blort', 'D:\Blort2')
/* Moves 'C:\Blort' to 'D:\Blort2' */
MOVEFILE('C:\MyDir\', 'C:\MyDir2\')
/* Moves all files in 'C:\MyDir' to 'C:\MyDir2' */
MOVEFILE('C:\*.bak', 'C:\MyDir\')
/* Moves all files in C:\ that end with .bak to 'C:\MyDir' */
MOVEFILE('*.bat', '*.bak')
/* Renames all files in the current directory that end with .bat, renaming them with a .bak extension.

See also

COPYFILE, DELETEFILE


PATH

Gets a full pathname from a partial name, queries the current directory, sets the current directory, splits a pathname into separate elements assigning each piece to a compound variable, and/or checks if a pathname is a drive/directory or file.

PATH() is akin to a combination of FILESPEC(), DIRECTORY(), QUALIFY(), and more, all wrapped up into one function. As such, it can replace those functions. It is supported only by Reginald.

Synopsis
error = PATH(varname, pathname, options)

Args

pathname is the name of a file or drive/directory. It may be fully qualified with drive and parent directory names, as well as any possible extension upon the file's name. For example, "C:\WINDOWS\NOTEPAD.EXE" includes all four elements -- the drive name "C:\", the directory names "WINDOWS\", the filename "NOTEPAD", and the extension ".EXE". Or, it may be a partial name. For example, "NOTEPAD.EXE" specifies only the filename and extension parts. The name may also include wildcards such as "C:\WINDOWS\*.INI" to specify any item in the C:\WINDOWS directory that has an extension of ".INI".

If you wish pathname to be split apart into its separate elements of drive, directories, filename, and extension, then varname is the name of the stem variable where those elements are returned. If varname is omitted, then pathname is simply the name of where you would like the current directory to be set.

Note: Don't forget to put quotes around varname, and do not end it with a dot.

options may be any of the following:

Option
Meaning
'V' Check whether pathname is an existing drive/directory name, or a filename, before parsing it into separate elements.
'J' Join the filename and extension elements together in one variable, instead of separating the extension into its own variable.

Returns

An empty string if successful, or an error message if an error.

Notes

When pathname is separated into elements, the drive name is assigned to the stem variable with a ".0" extension, the directory names (if any) are assigned to the stem variable with a ".1" extension, the filename (if any) minus the extension is assigned to the stem variable with a ".2" extension, and the extension (if any) is assigned to the stem variable with a ".3" extension (unless the 'J' option is specified). So, if you pass a varname of 'MyVar', then the drive name is assigned to MyVar.0, the directory names (if any) are assigned to MyVar.1, the filename (if any) is assigned to MyVar.2, and the extension (if any) is assigned to MyVar.3 (assuming no 'J' option). If an element is not present in pathname, then its respective compound variable is an empty string. For example, if there is no extension, then MyVar.3 would be "".

How the drive and directories are specified in pathname may be platform dependent. Reginald will accept either a slash or backslash to separate directory names. When returning the separated elements, PATH() will ensure that those elements are properly formatted for the given operating system, such that they can be concatenated back together to form a legal pathname. For Windows, this means that the drive and directory names end with a backslash, and the extension begins with a dot. Reginald will also trim off any leading and trailing spaces from pathname upon operating systems where such spaces are not allowed.

Examples

To set the current directory, you will pass in pathname as the desired directory, and omit varname. For example, to set the current directory to "C:\WINDOWS', you would call PATH() as so:

error = PATH(, 'C:\WINDOWS')
IF error \== "" THEN SAY "ERROR:" error
You do not need to specify the full path. For example, assume that the current directory is "C:\WINDOWS". To set the current directory to the sub-directory "MyDir\MyName" inside of "C:\WINDOWS", you can call PATH() as so:
error = PATH(, 'MyDir\MyName')
IF error \== "" THEN SAY "ERROR:" error
This results in the current directory being C:\WINDOWS\MyDir\MyName, assuming that MyName is a directory. If MyName happens to be the name of an existing file, then it is trimmed off and the current directory is set to C:\WINDOWS\MyDir. This saves you the trouble of having to trim off the filename/extension from a path in order to set the directory (but only works if the file actually exists).

Note: If any of the parent directories do not exist, you will get an appropriate error message.

To split a name into separate elements, you need to supply varname. For example, to split the name "C:\MyDir\MySubDir\MyFile.Extension" into separate pieces and store those pieces into variables named MYSTEM.0, MYSTEM.1, MYSTEM.2, and MYSTEM.3, you would call PATH() as so:

error = PATH('MyStem', 'C:\MyDir\MySubDir\MyFile.Extension')
IF error \== "" THEN SAY "ERROR:" error
If successful, this would result in the following assignments:
MyStem.0 = 'C:\'
MyStem.1 = 'MyDir\MySubDir\'
MyStem.2 = 'MyFile'
MyStem.3 = '.Extension'
Use the 'V' option if you need to verify whether pathname is an existing drive/directory, or a filename (for a file that may or may not exist). For example, consider splitting apart "C:\MyDir\MySubDir\MyFile.Extension", and let's assume that MyFile.Extension is an existing directory inside of C:\MyDir\MySubDir. Now call PATH() with the 'V' option:
error = PATH('MyStem', 'C:\MyDir\MySubDir\MyFile.Extension', 'V')
IF error \== "" THEN SAY "ERROR:" error
If successful, this would result in the following assignments:
MyStem.0 = 'C:\'
MyStem.1 = 'MyDir\MySubDir\MyFile.Extension\'
MyStem.2 = ''
MyStem.3 = ''
Note that MyFile.Extension is now considered part of the directory names, which end with a backslash. And the filename and extension parts are now empty strings. In this way, you can test whether MyStem.2 and MyStem.3 are empty to determine whether you have an existing directory name. Of course, if you instead have a filename, that file may or may not exist. You can then use STATE() to verify its existence, or try to open the file with STREAM()'s 'OPEN READ' to verify if it exists, as so:
error = PATH('MyStem', 'C:\MyDir\MySubDir\MyFile.Extension', 'V')
IF error \== "" THEN SAY "ERROR:" error
ELSE DO

   /* Is it an existing directory? */
   IF MyStem.2 == "" & MyStem.3 == "" THEN SAY "It's a directory."

   /* It's a filename. */
   ELSE DO

      /* Is it an existing file? */
      IF STATE() THEN SAY "It doesn't yet exist."
      ELSE SAY "It's a file."

   END

END
pathname may also contain wildcards. For example, consider this call:
error = PATH('MyStem', 'C:\MyDir\*.*', 'V')
IF error \= "" THEN SAY "ERROR:" error
If successful, this would result in the following assignments:
MyStem.0 = 'C:\'
MyStem.1 = 'MyDir\'
MyStem.2 = '*'
MyStem.3 = '.*'
You can also use the 'J' option if you don't wish the filename and extension parts separated, as so:
error = PATH('MyStem', 'C:\MyDir\*.INI', 'VJ')
IF error \= "" THEN SAY "ERROR:" error
If successful, this would result in the following assignments:
MyStem.0 = 'C:\'
MyStem.1 = 'MyDir\'
MyStem.2 = '*.INI'
MyStem.3 = ''
To query the current directory, and also parse it into separate elements of drive and directory names, you omit pathname, for example, assuming the current directory is "C:\WINDOWS":
error = PATH('MyStem')
IF error \= "" THEN SAY "ERROR:" error
If successful, this would result in the following assignments:
MyStem.0 = 'C:\'
MyStem.1 = 'WINDOWS\'
MyStem.2 = ''
MyStem.3 = ''
See also

MATCHNAME, FILESPEC, QUALIFY, DIRECTORY, CHDIR, STATE


QUALIFY

Gets a fully qualified name of a file/stream, complete with drive and directory names, from a partial pathname, for example, perhaps only the filename itself.

Synopsis
fullname = QUALIFY(name)

Args

name is the partial path name of the file/stream.

Returns

If successful, the fully qualified path name, complete with drive and directory names. If an error, an empty string (and SYNTAX condition is raised).

Notes

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names, and will substitute the proper character (on the returned fullname) for the given operating system. Reginald also trims leading/trailing spaces from name upon operating systems where such spaces are not allowed.

QUALIFY() constructs the full path name using the current drive and current directory. It does not check for the actual existence of such a file. If desired, use STATE or MATCHNAME (if name could contain wildcards) to verify if a file/stream by that name actually exists.

QUALIFY() works only upon persistent streams. A transient stream will raise a SYNTAX condition.

Not all interpreters support this function.

Examples

Example use
Return value
QUALIFY('Blort.txt') /* Assume current dir is C:\MyDir\MySubDir */
'C:\MyDir\MySubDir\Blort.txt'

See also

MATCHNAME, PATH


SEARCHPATH

Searches the specified path for the specified file/directory and returns the full path name of the file/directory if found. Also can be used to get the value of an environment variable, or special Windows directory.

Synopsis
fullname = SEARCHPATH(path, filename)

Args

filename is the file to search for. The wildcards * and ? can be used. * matches any amount of characters up to a \, :, or . (dot). ? matches any one character. If wildcards are used, they appear in the returned fullname. If filename is omitted, then only path is evaluated.

path is where to search for the file. If omitted, Windows searches default paths (including the WINDOWS and SYSTEM directories, as well as any environment variable paths). The path can contain an environment variable (which must be enclosed between two % characters). For example, assume that an environment variable called MYPATH is set to SomeDir\SomeSubDir. If you pass a path of C:\%MYPATH%\AnotherDir, then the fullname is evaluated to C:\SomeDir\SomeSubDir\AnotherDir.

Certain environment variables are already defined. They are:

Path
Meaning
'%WIN%' Returns the Windows directory.
'%SYS%' Returns the System directory.
'%PROGRAMS%' Returns the Program Files directory.
'%RECENT%' Returns the Recent Documents directory.
'%SENDTO%' Returns the Send To directory.
'%FONTS%' Returns the Fonts directory.
'%TEMP%' Returns the directory for temporary files.
'%DESKTOP%' Returns the path to the Current User's desktop.
'%DOCS%' Returns the path to the Current User's My Documents folder.
'%FAV%' Returns the path to the Current User's Favorites folder.
'%MENU%' Returns the Current User -> Start Menu's "Programs" folder.
'%STARTUP%' Returns the Current User -> Start Menu's "Programs" folder.
'%ADESKTOP%' Returns the path to All Users' desktop.
'%ADOCS%' Returns the path to All Users' Documents.
'%AMENU%' Returns All Users -> Start Menu's "Programs" folder.
'%ASTARTUP%' Returns All Users -> Start Menu's "Programs" folder.

Returns

The full path name of the file if it is found in the specified path. If the file can't be found, an empty string is returned. If filename is omitted, then the value of path is returned (with a \ character appended to the end. To omit this final character, pass an empty string for filename).

Notes

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names. Reginald also trims leading/trailing spaces from name upon operating systems where such spaces are not allowed.

Examples

SEARCHPATH() is typically used in two situations:

  1. Resolve environment variables, or retrieve the location of a special Windows directory. In this case, you pass the environment variable name (perhaps embedded within a directory spec) as the first arg. For example, to resolve a path that uses the environment variable %MYPATH% in it:
    name = SEARCHPATH('C:\%MYPATH%')
    IF name \== 'C:\%MYPATH%\' && name \== "" THEN SAY "Found it, and the path is" name
    
    As you can see from the second line above, an appropriate error check is to see that SEARCHPATH returned a fullname with the environment variable resolved.
  2. Search for a file (ie, retrieve its full name) when you have only the filename itself (or part of the path). In this case, you can pass that partial path as the second arg. For example, to locate the full path of the 'WIN.INI' file:
    name = SEARCHPATH(, 'WIN.INI')
    IF name \== "" THEN SAY "Found it, and the full path is" name
    
    As you can see from the second line above, an appropriate error check when you pass the second arg is to see that SEARCHPATH returned a non-empty fullname.

    Note that you can do both simultaneously above (ie, pass an environment name as the first arg, and a filename as the second arg, and come up with the complete path of that file with the environment variable resolved).

    /* Search for a 'rxdlg.dll' along LIBPATH */
    name = SEARCHPATH('%LIBPATH%', 'rxdlg.dll')
    
    /* found it? */
    IF name \== "" THEN SAY "Found it"
    

See also

MATCHNAME, QUALIFY, PATH


STATE

Tests if a file/stream actually exists.

Synopsis
result = STATE(name)

Args

name is the name of the file/stream whose existence is to be checked.

Returns

0 if the stream exists, or 1 if it does not exist.

Notes

How the drive and directories are specified may be platform dependent. Reginald will accept either a slash or backslash to separate directory names. Reginald also trims leading/trailing spaces from name upon operating systems where such spaces are not allowed.

STATE() can also be used to check for the existence of a directory, but cannot report whether name is an existing directory or file. Use MATCHNAME instead if it is important to also determine the attributes for name (such as whether it is a directory or file, read-only, hidden, etc).

If name could contain wildcard characters, then use MATCHNAME instead to test for the existence of a matching file/directory. STATE() does not take wildcard characters into consideration.

Examples

Example use
Return value
STATE('C:\MyDir\MySubDir\Blort.txt')
/* Determines if 'C:\MyDir\MySubDir\Blort.txt' exists */

See also

MATCHNAME, QUALIFY


STREAM

Opens/closes/seeks streams, and reports stream diagnostics/information.

Synopsis
result = STREAM(stream, option, command)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names).

option specifies which task you wish STREAM() to perform. It must be one of the following:

Option
Meaning
C (Command) Executes a command. The command arg to STREAM() will specify which command.
S (Status) Returns the string 'READY' if the stream is open and more data can be read from, or written to, the stream. Returns the string 'NOTREADY' if the "read character" and "read line" pointers are already at the end of the stream and a further call to LINEIN() or CHARIN() would cause a NOTREADY error. Returns the string 'ERROR' if the last operation caused the stream to be in error state. When a stream is in error state, calls to functions such as LINEIN(), LINEOUT(), CHARIN(), and CHAROUT() seem to indicate successful operation, but no actual operation is carried out. You must issue a STREAM() RESET command on the stream in order to clear its error state before any actual operations can resume. Returns the string 'UNKNOWN', if a stream has not yet been accessed by REXX.
D (Description) Returns any error message associated with the last operation performed upon the stream. If there was no error, then an empty string is returned.

If option is omitted, it defaults to 'S'.

command is specified only when option is 'C'. It must be one of the following:

Option
Meaning
CLOSE Close the stream. If successful, return an empty string. If an error, raise NOTREADY and return the string 'ERROR: xxx' where xxx is replaced by some error number from the operating system. STREAM()'s 'D' option may yield a more specific error message.
FLUSH Flush any data in the operating system's I/O buffers. If successful, return the string 'READY'. If an error, raise NOTREADY and return 'ERROR'. STREAM()'s 'D' option may yield a more specific error message. If the stream was not open, return 'UNKNOWN'.
OPEN READ Open an existing stream for reading only (ie, CHARIN(), LINEIN()). Place the "read line" and "read character" pointers at the start of the stream. If successful, return the string "READY:". If an error (including if the stream doesn't exist), raise NOTREADY and return the string 'ERROR: xxx' as per the CLOSE command. Other programs may also open the stream for reading (ie, shared read access), but not shared write access.
OPEN WRITE Open the stream for writing only (ie, CHAROUT(), LINEOUT()). If the stream does not exist, create it. If it exists, retain its existing data. Place the "write line" and "write character" pointers at the end of the stream. If successful, return the string "READY:". If an error, raise NOTREADY and return the string 'ERROR: xxx' as per the CLOSE command. No other program may be simultaneously accessing the stream while your script has this stream open (ie no shared access).
OPEN BOTH Open the stream for both reading and writing. If the stream does not exist, create it. If it exists, retain its existing data. Place the "read line" and "read character" pointers at the start of the stream, and the "write line" and "write character" pointers at the end of the stream. If successful, return the string "READY:". If an error, raise NOTREADY and return the string 'ERROR: xxx' as per the CLOSE command. No other program may be simultaneously accessing the stream while your script has this stream open (ie no shared access).
OPEN BOTH SHARED This is the same as 'OPEN BOTH', except that other programs may also open the stream for reading/writing (ie, shared access). This is supported only by Reginald.
OPEN WRITE APPEND Open the stream for writing only. If the stream does not exist, create it. If it exists, retain its existing data. Place the "write line" and "write character" pointers at the end of the stream. You are not allowed to set the position in this stream. (It is assumed to be a transient stream). If successful, return the string "READY:". If an error, raise NOTREADY and return the string 'ERROR: xxx' as per the CLOSE command. No other program may be simultaneously accessing the stream while your script has this stream open (ie no shared access).
OPEN WRITE REPLACE Open the stream for writing only. If the stream does not exist, create it. If it exists, delete any previous contents of the stream. Place the "write line" and "write character" pointers at the start of the stream. If successful, return the string "READY:". If an error, raise NOTREADY and return the string 'ERROR: xxx' as per the CLOSE command. No other program may be simultaneously accessing the stream while your script has this stream open (ie no shared access).
OPEN BOTH APPEND Open the stream for both reading and writing. If the stream does not exist, create it. If it exists, retain its existing data. Place the "read line" and "read character" pointers at the start of the stream, and the "write line" and "write character" pointers at the end of the stream. You are not allowed to set the position in this stream. (It is assumed to be a transient stream). If successful, return the string "READY:". If an error, raise NOTREADY and return the string 'ERROR: xxx' as per the CLOSE command. No other program may be simultaneously accessing the stream while your script has this stream open (ie no shared access).
OPEN BOTH REPLACE Open the stream for both reading and writing. If the stream does not exist, create it. If it exists, delete any previous contents of the stream. Place the "read line", "read character", "write line", and "write character" pointers at the start of the stream. If successful, return the string "READY:". If an error, raise NOTREADY and return the string 'ERROR: xxx' as per the CLOSE command. No other program may be simultaneously accessing the stream while your script has this stream open (ie no shared access).
OPEN WRITE SHARED This is the same as 'OPEN BOTH REPLACE', except that other programs may also open the stream for reading/writing (ie, shared access). This is supported only by Reginald.
RESET Clears a stream's error state. If successful, and the stream is ready to operate again, returns the string 'READY'. If an error, returns the string 'UNKNOWN', and you will need to open the stream again.
READABLE Returns 1 if read permission is allowed on the stream. Returns 0 otherwise.
WRITABLE Returns 1 if write permission is allowed on the stream. Returns 0 otherwise.
EXECUTABLE Returns 1 if the stream is an executable. Returns 0 otherwise.
STATUS Returns a string containing information about the stream as so:

'<mode> READ: char= <rcharno> line= <rlineno> WRITE: char= <wcharno> line= <wlineno> <type>'

where: <mode> = "READ/WRITE", "READ", or "WRITE"
<rcharno> = Current read character position (0 is first char)
<rlineno> = Current read line position (1 is first line)
<wcharno> = Current write character position
<wlineno> = Current write line position
<type> = "PERSISTENT" or "TRANSIENT"

If an error, returns an empty string.

FSTAT If successful, return a string from the operating system containing information about the stream, including how much data it contains (or its free space in the case of a drive), its permission bits, and other operating system specific info. If an error (including if the stream doesn't exist), return an empty string.
QUERY DATETIME If successful, return a string containing the date/time that the stream was last modified. The format is Month-Day-Year Hour:Minute:Second, where the year is 2 digits. If an error, return an empty string.
QUERY TIMESTAMP If successful, return a string containing the date/time that the stream was last modified. The format is Year-Month-Day Hour:Minute:Second, where the year is 4 digits. If an error, return an empty string.
QUERY EXISTS If successful, return the fully qualified path name of the stream. If an error, return an empty string.
QUERY HANDLE If successful, return the handle of the stream if it is open by REXX. If an error (or the handle is not open by REXX), return an empty string.
QUERY POSITION READ If successful, return the current position of the "read character pointer" for the stream, where 0 is the first character in the stream. If an error, return an empty string.
QUERY POSITION WRITE If successful, return the current position of the "write character pointer" for the stream, where 0 is the first character in the stream. If an error, return an empty string.
QUERY POSITION READ CHAR Same as QUERY POSITION READ.
QUERY POSITION WRITE CHAR Same as QUERY POSITION WRITE.
QUERY POSITION READ LINE If successful, return the current position of the "read line pointer" for the stream, where 1 is the first line in the stream. If an error, return an empty string.
QUERY POSITION WRITE LINE If successful, return the current position of the "write line pointer" for the stream, where 1 is the first line in the stream. If an error, return an empty string.
QUERY POSITION SYS If successful, return the current position of the "read character pointer" for the stream as reported by the operating system, where 0 is the first character in the stream. If an error, return an empty string. This may ultimately be more accurate than QUERY POSITION READ.
QUERY SIZE If successful, return the size of the stream in bytes. If an error, return an empty string.
QUERY STREAMTYPE If successful, return the stream's type -- either 'TRANSIENT', 'PERSISTENT', or 'UNKNOWN' (if REXX has not accessed it). If an error, return an empty string.
SEEK <offset> READ CHAR Set the "read character pointer" to a new position. <offset> is that new position. This can be signed number if seeking backward/forward a specific number of characters from the current position. For example, -2 would seek two bytes less than the current position. To use the end of the stream as a reference point, preface the position with a < character. For example, <5 would set the read character pointer to 5 characters before the end of the stream. To use the start of the stream as a reference point, preface the position with a > character. For example, >10 would set the read character pointer to the tenth character in the stream. If successful, STREAM() returns the new position of the "read character pointer" referenced from the start of the stream, where 0 is the first character in the stream. If an error, raises NOTREADY, and returns an empty string.
SEEK <offset> READ LINE Set the "read line pointer" to a new position. <offset> is that new position. This can be signed number if seeking backward/forward a specific number of lines from the current position. For example, -2 would seek two lines less than the current position. To use the end of the stream as a reference point, preface the position with a < character. For example, <5 would set the read line pointer to 5 lines before the end of the stream. To use the start of the stream as a reference point, preface the position with a > character. For example, >10 would set the read line pointer to the tenth line in the stream. If successful, STREAM() returns the new position of the "read line pointer" referenced from the start of the stream, where 1 is the first line in the stream. If an error, raise NOTREADY and return an empty string.
SEEK <offset> WRITE CHAR Similiar to SEEK READ CHAR, except this sets the "write character pointer" to a new position.
SEEK <offset> WRITE LINE Similiar to SEEK READ LINE, except this sets the "write line pointer" to a new position.

Returns

Depends upon option (and possibly command). See above.

Notes

If a NOTREADY condition is raised, your NOTREADY handler can use CONDITION('D') to return the name of the stream in error (and then use STREAM's 'D' option to fetch an informative error message).

Some REXX interpreters may support other STREAM() options/commands, and may not support some of the ones listed above.

It is best to explicitly open a stream with one of STREAM's OPEN commands, and then close it with STREAM's CLOSE command after you're done using the stream.


VALUEIN

Reads in a numeric value from a binary (ie, non-text) file.

Synopsis
value = VALUEIN(stream, position, length, options)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to read from STDIN.

position specifies at what character position (within the stream) to start reading from, where 1 means to start reading at the very first character in the stream. If omitted, the default is to resume reading at where a previous call to CHARIN() or VALUEIN() left off (or where you set the "read character pointer" via STREAM's SEEK).

length is a 1 to read in the next binary byte (ie, 8-bit value), a 2 to read in the next binary short (ie, 16-bit value), or a 4 to read in the next binary long (ie, 32-bit value). If length is omitted, VALUEIN() defaults to reading a byte.

options can be any of the following:

Option
Meaning
M The value is stored (in the stream) in Motorola (big endian) byte order, rather than Intel (little endian) byte order. The effects only long and short values.
H Read in the value as hexadecimal (rather than the default of base 10, or decimal, which is the base that REXX uses to express numbers). The value can later be converted with X2D().
B Read in the value as binary (base 2).
- The value is signed (as opposed to unsigned).

If omitted, options defaults to none of the above.

Returns

The value, if successful. If an error, an empty string is returned (unless the NOTREADY condition is trapped via CALL method. Then, a '0' is returned).

Notes

Most REXX stream functions such as CHARIN() and LINEIN() assume that you'll be reading text (ie, ascii) files. So, for example, if the file contains the value 135, then it will actually contain the 3 ascii characters (ie, bytes) of '1', '3', and '5'. But some data files that you need to read may be binary files. For example, the 135 value may be stored as one, binary byte. VALUEIN() can be useful to read values from such a file since it automatically translates a byte, short, or long in the file to the equivalent REXX numeric string.

You may use the CHARS function to determine how many remaining characters are available to be read, before calling VALUEIN().

If the operating system has a problem reading from the stream, then this raises a NOTREADY condition.

After a call to VALUEIN(), you can use STREAM's 'D' option to return an informative error message as to the nature of any error that may have occurred. This will return an empty string if there was no error. Otherwise, unless you SIGNAL ON NOTREADY, it may be difficult to distinguish between an error occuring, or reaching the end of a persistent stream.

If a NOTREADY condition is raised, your NOTREADY handler can use CONDITION('D') to return the name of the stream in error (and then use STREAM's 'D' option to fetch an informative error message).

For a transient stream (such as STDIN):

You cannot specify a position, or this raises a SYNTAX condition with ANSI error of 40.42.

If there are not as many characters available as how many required to return the value you have requested, then program execution may stop until the requested number of characters are available. Execution will resume when the requested characters are finally made available (or the user aborts via CTRL-C which will raise a HALT condition). Otherwise, VALUEIN() may return an empty string and raise NOTREADY.

For a persistent stream:

If position is beyond the last character in the stream, then this raises a NOTREADY condition, and VALUEIN() will return an empty string.

If there are not as many characters available as how many required to return the value you have requested, then program execution may stop until the requested number of characters are available. Execution will resume when the requested characters are finally made available (or the user aborts via CTRL-C which will raise a HALT condition). Otherwise, VALUEIN() may return an empty string and raise NOTREADY.

Examples

Example use
Return value
CHARIN('myfile', , 2)
/* Reads the next short from 'myfile' */
CHARIN('myfile', , 4, '-')
/* Reads the next signed long from 'myfile' */

See also

CHARIN, CHARS


VALUEOUT

Write out numeric values to a binary (ie, non-text) file (ie, in non-text format).

Synopsis
result = VALUEOUT(stream, values, position, size,options)

Args

stream is the name of the stream. It can include the full path to the stream (ie, any drive and directory names). If omitted, the default is to write to STDOUT (typically, display the data in the console window).

position specifies at what character position (within the stream) to start writing the data, where 1 means to start writing at the very first character in the stream. If omitted, the default is to resume writing at where a previous call to CHAROUT() or VALUEOUT() left off (or where the "write character pointer" was set via STREAM's SEEK).

values are the numeric values (ie, data) to write out. Each value is separated by one space.

size is a 1 if each value is to be written as a byte (ie, 8-bit value), 2 if each value is to be written as a short (16-bit value), or 4 if each value is to be written as a long (32-bit value). If omitted, size defaults to 1.

options can be any of the following:

Option
Meaning
M Write out the values in Motorola (big endian) byte order, rather than Intel (little endian) byte order. The effects only long and short values.
H The values you supplied are specified in hexadecimal.
B The values you supplied are specified in binary (base 2).

If omitted, options defaults to none of the above.

Returns

0 if the string was written out successfully. If an error, VALUEOUT() returns non-zero.

Notes

If the operating system has a problem writing to the stream, then this raises a NOTREADY condition, and VALUEOUT() will return non-zero.

After a call to VALUEOUT(), you can use STREAM's 'D' option to return an informative error message as to the nature of any error that may have occurred. This will return an empty string if there was no error.

Program execution will stop until all requested data has been written to the stream (or the user aborts via CTRL-C which will cause a HALT error).

You can intermingle calls to VALUEOUT() with calls to CHAROUT(), upon the same string, if you wish to write out strings of ASCII characters intermingled with binary values.

If a NOTREADY condition is raised, your NOTREADY handler can use CONDITION('D') to return the name of the stream in error (and then use STREAM's 'D' option to fetch an informative error message).

For a transient stream (such as STDIN):

You cannot specify a position, or this raises a SYNTAX condition with ANSI error of 40.42.

For a persistent stream:

If position is beyond the immediate end of the stream (ie, more than one character beyond the last character already in the stream), then this raises a NOTREADY condition and VALUEOUT() returns non-zero.

Examples

Example use
Return value
VALUEOUT('myfile', 3000, , 2)
/* Writes the value 3000 to 'myfile' as a short */
VALUEOUT('myfile', 'F60', , 4, 'HM')
/* Write the hex value F60 to 'myfile' as a long in Motorola format */

See also

CHAROUT


More examples and notes
/* Print all words in a file */
filename = 'C:\mytext.txt'

/* Open the file for reading, but only if it exists */
IF STREAM(filename, 'C', 'OPEN READ') == 'READY:' THEN DO

   /* Use LINES() == 1 to indicate more lines */
   OPTIONS 'FAST_LINES_BIF_DEFAULT'

   /* Set up for any errors */
   SIGNAL ON NOTREADY NAME FileError

   /* Any more lines? */
   DO WHILE LINES(filename) > 0

      /* Read the next line */
      line = LINEIN(filename, , 1)

      /* Count how many words in this line */
      words = WORDS(line)

      /* SAY each word */
      DO i = 1 TO words
         SAY WORD(line, i)
      END

   END /* WHILE LINES() */

FileError:
   /* Close the file */
   CALL STREAM filename, 'C', 'CLOSE'

END /* STREAM() */

/* File can't be opened. SAY why */
ELSE SAY STREAM(filename, 'D')
RETURN

/* Read all the lines of a text file into a
 * stem variable named MyVar, where MyVar.0 tells how
 * many lines there are, and MyVar.1 to MyVar.xxx are
 * those lines.
 */
filename = 'C:\mytext.txt'

/* Initially no lines read */
lineno = 0

/* Open the file for reading, but only if it exists */
IF STREAM(filename, 'C', 'OPEN READ') == 'READY:' THEN DO

   /* Use LINES() == 1 to indicate more lines */
   OPTIONS 'FAST_LINES_BIF_DEFAULT'

   /* Set up for any errors */
   SIGNAL ON NOTREADY NAME FileError

   /* Any more lines? */
   DO WHILE LINES(filename) > 0

      i = lineno + 1

      /* Read the next line */
      MyVar.i = LINEIN(filename, , 1)

      /* Increment line count now that it is successfully read */
      lineno = i

   END /* WHILE LINES() */

FileError:
   /* Close the file */
   CALL STREAM filename, 'C', 'CLOSE'

END /* STREAM() */

/* File can't be opened. SAY why */
ELSE SAY STREAM(filename, 'D')

/* Store line count */
MyVar.0 = lineno
RETURN
Note that Reginald offers a LOADTEXT() function that does all of the above with a single call as so:
/* Read all the lines of a text file into a
 * stem variable named MyVar, where MyVar.0 tells how
 * many lines there are, and MyVar.1 to MyVar.xxx are
 * those lines.
 */
filename = 'C:\mytext.txt'
CALL LOADTEXT('MyVar.', filename)
RETURN

/* Write out all the lines to a text file from
 * a stem variable named MyVar, where MyVar.0 tells how
 * many lines there are, and MyVar.1 to MyVar.xxx are
 * those lines.
 */
filename = 'C:\mytext.txt'

/* Initially no lines written */
lineno = 0

/* Open/create the file, and overwrite any old contents */
IF STREAM(filename, 'C', 'OPEN WRITE REPLACE') == 'READY:' THEN DO

   /* Any more lines? */
   DO WHILE lineno < MyVar.0

      /* Increment line count */
      lineno = lineno + 1

      /* Write the next line */
      IF LINEOUT(filename, MyVar.lineno) \= 0 THEN DO

         /* Display error message */
         SAY 'Error writing to"'||filename||'"'
         SAY STREAM(filename, 'D')

         /* Cause the DO WHILE to END */
         lineno = MyVar.0

      END

   END /* lineno < MyVar.0 */

   /* Close the file */
   CALL STREAM filename, 'C', 'CLOSE'

END /* STREAM() */

/* File can't be opened. SAY why */
ELSE SAY STREAM(filename, 'D')
RETURN

/* Read the entire contents of a file into a
 * variable named MyVar.
 */
filename = 'C:\mytext.txt'

/* Initially no bytes read */
size = 0

/* Open the file for reading, but only if it exists */
IF STREAM(filename, 'C', 'OPEN READ') == 'READY:' THEN DO

   /* Get the size in bytes */
   MyVar = STREAM(filename, 'C', 'QUERY SIZE')

   /* Anything to read in? */
   IF MyVar \= "" THEN DO

      size = MyVar

      /* Read in the bytes */
      MyVar = CHARIN(filename, 1, size)
      IF LENGTH(MyVar) \= size THEN DO
         /* Display error message */
         SAY 'Error reading to"'||filename||'"'
         SAY STREAM(filename, 'D')
      END

   END /* MyVar \= "" */

   /* Close the file */
   CALL STREAM filename, 'C', 'CLOSE'

END /* STREAM() */

/* File can't be opened. SAY why */
ELSE SAY STREAM(filename, 'D')

/* size = how many bytes, MyVar = contents of file */
RETURN

There are 4 possible positions that REXX maintains for a stream. There is the current read character position. That is the position in the stream at which CHARIN() reads. There is the current write character position. That is the position in the stream at which CHAROUT() writes. (Remember that REXX streams which are open for both reading and writing -- ie, ones with which you've used both input functions such as CHARIN as well as output functions such as CHAROUT -- have 2 positions; a read position and a write position). There is the current read line position. That is the position in the stream at which LINEIN() reads. And finally, there is the current write line position. That is the position in the stream at which LINEOUT() writes.

The positions for CHARIN and CHAROUT (ie, the read character and write character positions) are expressed in terms of bytes. For example, if the current write character is 121, then the next time you call CHAROUT(), it will start writing characters beginning at the 121st byte of the stream.

The positions for LINEIN and LINEOUT (ie, the read line and write line positions) are expressed in terms of lines. For example, if the current write line is 12, then the next time you call LINEOUT(), it will write the line starting after the 11th line in the stream (ie, however many bytes in that happens to be).

When you call LINEOUT() with a line position, REXX seeks to that place in the stream in order to write out the line there. It implicitly (ie, transparent to the REXX script) updates both the current write line position as well as the current write character position. (So, you can actually query the current write character position after a call to LINEOUT() and find out exactly how many bytes you are into the stream). A call to CHAROUT() with a line position doesn't really update the current write line position, although it does sort of "change" it.

When you call LINEIN() with a line position, REXX seeks to that place in the stream in order to read in the line there. It implicitly updates both the current read line position as well as the current read character position. (So, you can actually query the current read character position after a call to LINEIN() and find out exactly which byte you will next read from the stream). A call to CHARIN() with a line position doesn't really update the current read line position, although it does sort of "change" it..

So, depending upon whether you're need to save the current read character position, the current write character position, the current read line position, or the current write line position, depends upon whether you're trying to save/restore the current position used for CHARIN(), CHAROUT(), LINEIN(), or LINEOUT() respectively.

REXX uses:

read_position = STREAM(some_stream_name, 'C', 'QUERY POSITION READ')
to return the current read character (CHARIN) position.

REXX uses:

write_position = STREAM(some_stream_name, 'C', 'QUERY POSITION WRITE')
to return the current write character (CHAROUT) position.

REXX uses:

write_position = STREAM(some_stream_name, 'C', 'QUERY POSITION, READ LINE')
to return the current read line (LINEIN) position.

REXX uses:

write_position = STREAM(some_stream_name, 'C', 'QUERY POSITION, WRITE LINE')
to return the current write line (LINEOUT) position.

So, for example, if the person wanted to save the current read character position, and then restore it for a later call to CHARIN, it would be something like this:

filename = 'C:\MYFILE'
/* Get current CHARIN position */
read_position = STREAM(filename, 'C', 'QUERY POSITION READ')

/* Here you may do some more calls to CHARIN() which will change
 *  the current read character position. So too, calls to LINEIN() will
 *  change that position.
 */

/* Read the character at the earlier, saved position again */
CALL CHARIN(filename, read_position)