home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 18 REXX
/
18-REXX.zip
/
filerx11.zip
/
filerexx.INF
(
.txt
)
< prev
next >
Wrap
OS/2 Help File
|
1995-09-22
|
87KB
|
2,865 lines
ΓòÉΓòÉΓòÉ 1. Introduction ΓòÉΓòÉΓòÉ
Please read this document in entirety. I took the time to make it explicit,
clear, and very useful. It took me longer to write it than it will ever take
you to read it. Therefore, you owe it to both of us to read it. OK?
FILEREXX.DLL is a REXX Function Library. It adds "commands" to the REXX
language, which a REXX script (ie, program) can call. These commands offer
alternatives to the REXX file reading/writing routines which make it possible
to access the same files from multiple running scripts (ie, allow file
sharing). FileRexx also makes it much easier to read/write files containing
binary values. There are also routines which vastly simplify device (ie,
driver) I/O, and make some driver control possible which standard REXX doesn't
allow. Finally, FileRexx offers a lot more parsing options when reading a
line, thus eliminating the need to parse a line into separate pieces, or using
TRANSLATE to change the case.
REXX has standard functions for opening files and reading/writing to those
files. The STREAM command is used to open a file. Then, data is read from
and/or written to the file via other standard functions such as CHAROUT,
CHARIN, LINEOUT, etc.
The STREAM command opens a file without allowing READ or WRITE sharing. What
this means is that another program cannot have that file open simultaneously.
Normally, you don't want two programs to be simultaneously writing to a file
under a true multi-tasking OS, since data that one program is writing may be
overwritten by the other program when a task switch occurs. If the programs
are appending data to the end of the file, the result could be an arbitrary
intermixing of data from the two programs. So, preventing WRITE access is a
foolproof way to make sure that this situation doesn't happen, and this is
completely implemented by the OS (ie, it's transparent to the program).
Likewise, a program that is writing to a file may wish to prevent READ sharing,
so that other programs don't open and read from the file while its contents are
changing. (A program that only reads from a file, and doesn't write to that
file, doesn't need to worry about sharing access. After all, the contents of
the file will be in a static state unless some program writes to that file.
Normally, only a program that writes to a file specifies that sharing is to be
prevented. Usually, such a program will open the file, write data to it, and
then close that file as soon as possible so that other programs can
subsequently open and access the file).
The REXX STREAM command prevents both READ and WRITE sharing because REXX
doesn't know whether your program is going to read from or write to that
stream. The STREAM command can be used both with functions that read from the
file (ie, CHARIN) and functions that write to the file (ie, CHAROUT). So, REXX
assumes that preventing READ and WRITE sharing is the safest approach with the
STREAM command. Unfortunately, this means that if any other program has a
particular file open, a REXX script can't open that file, even if the other
program is allowing sharing, because the STREAM command itself doesn't allow
that.
A situation arose where a sysop wanted to write a REXX script that read the
contents of a "configuration" file that some BBS software created. The BBS
software kept this file open all of the time that the software was running.
Unfortunately, this meant that the STREAM command could not open that file
while the BBS was running. This sysop asked me to write a REXX Function
Library that contained new REXX commands for opening, reading, and writing
files, allowing shared access. (Actually, he BEGGED me. He whimpered and
sobbed and offered his family pet for sexual favors. After all, he's a sysop).
Being the nice guy that I am (and also his french poodle is quite attractive),
I did so.
Furthermore, these configuration files contained binary values (ie, not just
ascii text). Because REXX needs to express all numeric variables as strings of
ascii digits (ie, a REXX variable with the value 147 is actually stored
internally as the string "147"), his REXX script had to read in each character
and convert it to an ascii digit. To avoid all of this hassle, I added two
functions to the DLL to make it easy to read or write a binary CHAR (8-bit),
SHORT (16-bit), or LONG (32-bit) value, signed or unsigned, to/from a file.
Finally, REXX has no facilities for controlling a device via DosDevIOCtl() (ie,
the device specific commands, such as the ASYNC RS232-C Control functions,
which can control a COM driver). So, I added FileDevIOCtl(), a function that
allows you to create a generic call to DosDevIOCtl(), thereby doing driver
specific operations with most any driver. In fact, you could even use FILEREXX
to create a REXX script to fully test the IOCTL interface of any driver that
you may be developing, or to develop applications which use that driver.
(Along with RXDLG.DLL, my Presentation Manager Interface for REXX, you could
even develop PM apps for your driver).
In conclusion, FILEREXX offers a more direct interface to OS/2's file system
than standard commands such as STREAM, LINEIN, LINEOUT, etc, and therefore
offers more control over such things as file sharing and device I/O, plus it
has a few functions that make it easy to read/write binary files and
send/receive binary values to device drivers, and some extra line parsing
features that LINEIN doesn't have.
This is version 1. Don't worry. It shouldn't kill you.
Some of the words in this manual are highlighted in bold text, such as STREAM.
These refer to REXX commands, either standard ones, or new commands that the
FILEREXX DLL makes available to a REXX program. Other words are in italics
such as FileHandle. These refer to REXX variable names (ie, data within a REXX
program). Words that are in colored text such as Read This are meant to be
emphasized.
ΓòÉΓòÉΓòÉ 2. Copyright ΓòÉΓòÉΓòÉ
This OS/2 Online Book and the related files FILEREXX.DLL, and REXX scripts
written by Jeff Glatt are all copyright 1995 by Jeff Glatt. These files are
freely redistributable, and may be used by and distributed along with any
software, be it commercial or otherwise, provided that these files are not
internally modified, nor specifically sold as a complete product by themselves.
The only price that you have to pay is the one that you're already paying by
spending all of your time in front of a computer instead of developing
healthier outlets.
NOT SO STANDARD DISCLAIMER:
These programs are provided "as is" without warranty of any kind either
expressed or implied or tatooed in a place that only a few people have ever
seen, including but not limited to the implied warranties of merchantability,
fitness for a particular purpose, and the dubious assumption that the software
has been created by a sane individual who would never do anything that may hurt
you. The entire risk as to the results and performance of the programs is
assumed by you or someone who looks exactly like you. Jeff Glatt does not
guarantee that the functions in these programs will meet your requirements,
especially if your requirements involve lots of latex and some docile,
domesticated animal. Nor does Jeff Glatt warranty the programs to be
uninterruptable or error-free, although mercifully free of "General Protection
Faults". If you use said programs, you can not say anything nasty about the
author, even if the programs inadvertently cause the erasure of your collection
of X-rated GIFs of a conservative, overweight and overrated TV "personality"
plooking himself vigorously with his royalty checks from some rancid paperback.
Jeff Glatt is not responsible for any damages as a result of anything that he
has done, or hasn't done, or was supposed to do but never got around to it, and
furthermore, he doesn't even care so leave him alone, ratface. You may have
more or less protections in certain states of the union, depending upon how far
your local politician is willing to bend over for some bribe from a business
lobbyist. Just remember that Jeff Glatt has no money, so don't bother suing
him as a result of any damages caused by this OS/2 program. Tell your greasy
lawyer to go after IBM, and make sure that you pick 12 really stupid pinheads
for the jury. If swallowed, induce vomiting immediately by contemplating the
asthetics of Microsoft Windows.
OS/2 is a trademark of International Business Machines Corporation.
Windows is a trademark of Microsoft Incorporated, and furthermore, Bill Gates
is to blame for it.
If you have unreasonably presumptuous suggestions (ie, an enduser who expects
outrageous amounts of free support), snide comments, criticisms, and anything
else other than dollar bills, then send them to someone else because you got it
for free, and you know what you get for nothing? On the other hand, any type
of positive contribution from other programmers is very much welcome and
encouraged as these are the only folks who can made things happen for OS/2.
IBM ain't gonna do it. If you do need to contact the author, then either phone
some of the more prominent psychiatrict clinics in central New York state, or
try this:
Jeff Glatt
6 Sycamore Drive East
New Hartford, NY 13413
(315) 735-5350
Sure, this copyright notice has attitude. Get used to it, or kill yourself.
ΓòÉΓòÉΓòÉ 3. Installing and initializing FILEREXX ΓòÉΓòÉΓòÉ
FILEREXX.DLL should be copied to some directory along the LIBPATH specified in
your config.sys file. That way, REXX will be able to find it when your REXX
script references it.
In order to be able to call a given function in FILEREXX, your script must
first register that DLL function with REXX. You do this using the standard
REXX command RXFUNCADD. That function takes the name of the DLL which contains
the function (minus the .DLL extension), in this case FILEREXX, the name of the
function that you wish to call within the DLL (a list of available functions
will follow in this document), and the name that you'd like to assign to that
function (ie, so that your script can call it using a name different than its
real name).
FILEREXX has a special function called FILELOADFUNCS. A call to this one
function causes it to register all of the other functions in the DLL. This
means that you don't have to do a separate RXFUNCADD for every FILEREXX
function that you wish to call. Of course, you do have to initially call
RXFUNCADD for FILELOADFUNCS, so that you can call this one FILEREXX function
initially. Here's an example REXX script that does a RXFUNCADD on
FILELOADFUNCS, and then calls FILELOADFUNCS. After this, the REXX script may
call any other functions in FILEREXX.
CALL RxFuncAdd 'FileLoadFuncs', 'FILEREXX', 'FileLoadFuncs'
CALL FileLoadFuncs
ΓòÉΓòÉΓòÉ 4. FILEREXX Functions ΓòÉΓòÉΓòÉ
Here are the FILEREXX functions that you can call. Each function is on its own
page. The name of the function is in the title bar of the window. Listed on
the page below is its syntax (ie, what parameters you pass to it and what it
returns), as well as an example of its use. You'll note that all functions
begin with the letters File.
The functions are broken up into subsections. From example, all of the
functions that concern writing data to a file or device (as opposed to, for
example, listing or processing the name of a file) are under the heading
Writing Data to a File/Device.
If any of the functions are passed a zero handle (ie, an error return from
FileOpen), then they usually perform no work upon that handle. Always do error
checking upon the returns from FILEREXX functions. Failure to supply required
arguments (or invalid arguments) cause a REXX error condition. Other file
system errors do not cause a REXX error condition, but return an appropriate
error number to your script. For example, if a device returns some error to
FileDevIOCtl(), then that error number is returned by FileDevIOCtl(), but the
REXX ERROR or FAILURE Flags aren't set. It's up to the script to check
returned values for any errors in performing an operation.
ΓòÉΓòÉΓòÉ 4.1. DLL Setup and Cleanup ΓòÉΓòÉΓòÉ
These functions are used at the beginning and end of your REXX script, to
perform setup and cleanup of resources associated with using FILEREXX.
ΓòÉΓòÉΓòÉ 4.1.1. FileAddFuncs ΓòÉΓòÉΓòÉ
Syntax Call FileLoadFuncs
Args None
Returns None
Purpose Registers all of the REXX functions in FILEREXX.DLL, so that a
REXX script can subsequently call them without having to do a
separate RXFUNCADD for each desired function.
Examples CALL FileLoadFuncs
ΓòÉΓòÉΓòÉ 4.1.2. FileDropFuncs ΓòÉΓòÉΓòÉ
Syntax Call FileDropFuncs
Args None
Returns None
Purpose DeRegisters all of the REXX functions in FILEREXX.DLL. A REXX
script cannot subsequently call them, until it registers those
functions again. Normally, this is only used at the end of a
script to allow REXX to purge the DLL from memory after it is no
longer needed.
Examples CALL FileDropFuncs
ΓòÉΓòÉΓòÉ 4.2. Open/Close a File/Device ΓòÉΓòÉΓòÉ
FileOpen is used to open a file or device. You must open a file/device before
you use any functions that read or write data to that file/device, such as
FilePuts or FileGets, or other functions that require a file handle argument.
FileClose is used to close a file or device. You must close a file/device
after you're done writing or reading however much data that you desire from it.
Definitely close all (successfully) open files before your program ends. That
is to say, every time that FileOpen returns a non-zero handle to you, make sure
that you later pass that handle to FileClose once. A good approach is to have
separate "handle" variables for each file/device that you ever intend to open.
Set them all to 0 at the start of your program. Whenever you finally close the
handle, reset it to 0. Right before your program ends, check all of those
handle variables, and if any one isn't 0, pass it to FileClose. Example:
/* I intend to open 2 files and 1 device. So I have 3 handle variables.
Initially set them to 0 */
handle.1 = 0
handle.2 = 0
handle.3 = 0
Label:
/* Here you maybe open a file */
handle.1 = FileOpen('myfile')
IF handle.1 <> 0 THEN DO
/* Here you probably do something with that file */
/* Let's say that you're done using the file now. Close it, and reset the
handle variable */
IF FileClose(handle.1) = 0 THEN handle.1 = 0
END
/* OK, maybe you want to loop around for some reason */
SIGNAL Label
/* Here's where we end the program. Check all of the handles to make sure that
they're 0 */
DO i = 1 to 3 /* I had 3 handles */
IF handle.i <> 0 THEN CALL FileClose(handle.i)
END
Note: Handles returned by FileMatchFile should be closed by using
FileMatchFile rather than FileClose.
ΓòÉΓòÉΓòÉ 4.2.1. FileOpen ΓòÉΓòÉΓòÉ
Syntax handle = FileOpen(filename, mode, Flags, attributes)
Purpose Opens a file (or device driver) for reading and writing,
returning a file handle which the REXX script uses for calls to
other DLL functions. FileOpen is an alternative to using
STREAM.
Args filename is the complete filename (ie, with path, if desired) to
open. For example: 'c:\mydir\myfile'. This can also be the
name of a device driver, but you must use the internal name of
the driver, which may not necessarily be the same as its
filename on disk. (Usually, the internal name is simply the
driver's filename minus the .SYS extension).
mode is a string of characters where each character may be one
of the following:
'r' Allows reading from the file or driver (with FileRead,
FileGets, and FileReadValue). 'w' can be specified also if
writing is desired.
'w' Allows writing to the file or driver (with FileWrite,
FilePuts, and FileWriteValue). 'r' can be specified also if
reading is desired.
's' Sharing. Two characters may follow the 's'. These two
characters indicate the sharing status for READ and WRITE
respectively. Sharing is enabled if the character is '+', and
denied if the character is '-'. So, if you want READ sharing
with no WRITE sharing, you specify 's+-'. If you want no READ
sharing but with WRITE sharing, you specify 's-+'. If you want
no READ or WRITE sharing (ie, deny both), then you specify,
's--'. If you want both READ and WRITE sharing, you specify
's++', or simply 's' since that is considered the same as 's++'.
Sharing works like this. If you deny WRITE sharing, no other
program can have that file (or driver) open for writing,
although reading is OK, in order for your open to succeed, and
afterward, no other program can open the file for writing until
you close it, although another program can open it for reading.
If you deny READ sharing, no other program can have that file
open for reading, although writing is OK, in order for your open
to succeed, and afterward, no other program can open the file
for reading until you close it, although another program can
open it for writing. If you deny READ and WRITE sharing, no
other program can have that file open in order for your open to
succeed, and afterward, no other program can open that file
until you close it. If you don't deny READ and WRITE sharing
(and no other program has either), then any other program can
open the file.
'c' The opened file handle isn't passed on to child
processes.
'a' Sequential or Random Access. A '+' or '-' character
may follow the 'a'. If a '+', then Random Access is selected.
If a '-', then Sequential access is selected. 'a' is the same
as 'a-'.
'b' Output (ie, FileWrite, FileWriteValue, FilePuts) is not
put in the hardware cache.
'e' Report errors to caller. This is with the OS, not
between your script and FILEREXX.
'v' Do not return until output is written to the device.
If the mode arg is not supplied, it defaults to 'rs+-'. The
order of mode parameters is irrelevant.
Flags is a string of characters where each character may be one
of the following:
'v' Fail if the file/driver already exists. This can't be
specified along with any of the other 3 options.
'e' Open the file/driver if it exists, otherwise fail if
it does not.
'o' Overwrite any file that exists with the same name.
'n' Create a new file if one with this name doesn't
already exist.
If the Flags arg is not supplied, it defaults to 'e'. The
order of Flags is irrelevant.
attributes is the desired file attributes of the file, if
creating it. These can be any sensible combination of the
following (where you simply add the values that you desire):
0 Normal File or Driver
1 Read-Only
2 Hidden
4 System
16 Directory
32 Archived
If the attributes arg is not supplied, it defaults to 0
(Normal File).
Returns If this function was successful, the handle of the opened file
or driver is returned, and this will not be 0. This handle is
passed to other FILEREXX functions. The REXX variable, FileErr
is also set to the action taken by FileOpen, and can be one of
the following values:
1 file/driver existed
2 file was created
3 file length was truncated
If an error, a 0 is returned, and the REXX variable, FileErr is
set to 0.
Examples /* Open a file named 'c:\blort' for reading/writing. Specify
Flags as 'on' to overwrite any existing file with the same name,
or create a new file if it doesn't exist. Specify mode as 'rws'
in order to read and write to the file, and allow READ and WRITE
sharing. Specify attributes as 0 for normal file, although we
don't need to supply this arg as that's the default.
*/
handle = FileOpen('c:\blort', 'rws', 'on', 0)
IF handle = 0 THEN SAY 'error'
/* Open a file named 'myfile' for reading. Specify Flags as 'e'
to only open the file if it already exists. Specify mode as 'r'
in order to read from the file. Since we didn't specify
sharing, we accept the default of allowing READ sharing but no
WRITE sharing. Since the attributes arg is omitted, it defaults
to 0 for normal file. This could also be used to check if a file
exists before writing to that filename; if the returned handle
is 0, then you can open the file again for writing and create a
new file.
*/
handle = FileOpen('myfile', 'r', 'e')
IF handle = 0 THEN SAY 'error'
/* Same as above, since the default for mode is 'rs+-' and
default for Flags is 'e'.
*/
handle = FileOpen('myfile')
IF handle = 0 THEN SAY 'error'
/* Open a file named 'c:\blort' for writing. Specify Flags as
'n' to create a new file if it doesn't exist, but we aren't
going to overwrite any existing file. Specify mode as 'ws--' in
order to write to the file, and prevent READ and WRITE sharing.
*/
handle = FileOpen('c:\blort', 'ws--', 'n')
IF handle = 0 THEN SAY 'error'
/* Open the COM1 device driver for reading/writing. Allow both
read and write sharing.
*/
handle = FileOpen('COM1', 'rws')
IF handle = 0 THEN SAY 'error'
ΓòÉΓòÉΓòÉ 4.2.2. FileClose ΓòÉΓòÉΓòÉ
Syntax err = FileClose(handle)
Purpose Closes a file or driver that was opened with FileOpen. A
file/driver that is successfully opened with FileOpen must
always be closed after the REXX script is finished accessing the
file/driver.
Args handle is the opened handle as returned by FileOpen.
Returns If successful, a 0 is returned.
If an error, a non-zero value is returned which represents the
error number from DosClose.
Examples /* Open a file named 'myfile' for reading. */
handle = FileOpen('myfile', 'r', 'e')
IF handle = 0 THEN SAY 'error opening file'
err = FileClose(handle)
IF err <> 0 THEN SAY 'error closing file'
ΓòÉΓòÉΓòÉ 4.3. Read data from a File/Device ΓòÉΓòÉΓòÉ
These functions are used to read data from a file or device. You must open a
file/device with FileOpen before you use these functions. FileRead is used to
read individual (8-bit) characters, or a specific number of characters from a
file/device. It's essentially an equivalent to CHARIN. No translation is
performed upon the data. So if you happen to read a text file (ie, containing
ascii characters), you get ascii characters back. All REXX variables, even
numeric ones, are stored internally as ascii strings. So as long as you read
ascii data, you can perform math on any numeric values. But if you need to
read binary data (and most non-REXX programs and device drivers read/write
numeric data in binary), you should use FileReadValue. This automatically
reads a binary LONG (32-bit value), SHORT (16-bit value), or CHAR (8-bit)
value, translating it to an equivalent REXX ascii string. Finally, FileGets is
essentially an alternative to LINEIN, but with built-in parsing options.
ΓòÉΓòÉΓòÉ 4.3.1. FileRead ΓòÉΓòÉΓòÉ
Syntax contents = FileRead(handle, count)
Purpose Reads in 8-bit characters from an open file or driver, and
returns them to the REXX script. No translation is performed
upon the characters. So, if you read in a binary character of
6, then that's what is returned to your script. Remember that
REXX internally stores all variables as ascii strings, including
numeric variables, so if you want the returned string to be the
value 6, you'll have to convert the returned character into hex
36 (ie, an ascii '6'), or use FileReadValue instead. FileRead
is an alternative to using CHARIN for reading ascii text
characters from a file or driver.
Note: This function can be used in combination with FileGets,
FileReadBlock, or FileReadValue upon the same handle.
Args handle is the opened handle as returned by FileOpen.
count is the number of 8-bit characters to read. If not
supplied, this defaults to 1 (ie, for reading the next character
in the file/driver).
Returns If success, the requested number of characters are read from the
file/driver and returned to the REXX script. Note that some
drivers may cause the REXX script to be suspended if the driver
doesn't have as many characters as you've requested, until such
time as the requested number of characters are received by the
driver (by its device). Other drivers may do some sort of
timeout if it is necessary to wait for more characters, after
which the driver will return however many characters it could
fill of your request. Furthermore, if you try to read more
characters from a file than are remaining in the file, you'll
only get as characters as are remaining. So, it's possible to
get less characters back than you requested.
If an error or the end of file, a null string is returned.
Also, some drivers that have no characters ready to be read, but
which don't suspend the REXX script until the requested
characters are received, may return a null string.
Examples /* Open 'myfile' for reading */
handle = FileOpen('myfile')
IF handle <> 0 THEN DO
/* Read 10 characters and print them */
contents = FileRead(handle, 10)
IF contents <> "" THEN SAY contents
/* Read 1 more character */
contents = FileRead(handle)
IF contents <> "" THEN SAY contents
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.3.2. FileGets ΓòÉΓòÉΓòÉ
Syntax line = FileGets(handle, Flags, rightseparators, leftseparators)
Purpose Reads in one line of text from an open file/driver, returning
that to the REXX script. No translation is done on any of the
characters of the line (so this should be used merely as an
alternative to the standard REXX command LINEIN).
For parsing, this can break up the line into several pieces and
place those pieces in a stem variable for easy processing.
Note: A line limit of 256 characters is imposed. Trying to
read a longer line will result in the first 255
characters being returned as if that was the next line in
the file, and a subsequent call to FileGets will begin
reading on the 256th character of the oversized line. If
parsing, the 256 character limit applies to each arg, but
not the entire line.
Note: This function can be used in combination with FileRead,
FileReadBlock, or FileReadValue upon the same handle.
Args handle is the opened handle as returned by FileOpen.
Flags is a string containing any of the following:
't' Trim off spaces at the head and tail of the line (or
each arg if parsing the line).
's' Compress spaces (ie, replace all instances of more than
one space in a row, with one space).
'c' Make all letters (ie, A to Z) in the line (or each arg
if parsing the line) upper or lower case. If a '-' sign appears
after the 'c', that means lower case. If a '+' appears (or no
sign is specified), that's upper case.
'r' Step match rightseparators. Search for only the first
separator when parsing the first arg, search for only the second
separator when parsing the second arg, etc. If a '+' appears
after the 'r', then if there are more args in the line than
rightseparator characters, use the last separator character to
parse the extra args.
'l' Step match leftseparators. Search for only the first
separator when parsing the last arg, search for only the second
separator when parsing the next to last arg, etc. If a '+'
appears after the 'l', then if there are more args in the line
than leftseparator characters, use the last separator character
to parse the extra args.
If Flags is omitted (or a null string), the default is none
of the above. The order of Flags is irrelevant.
rightseparators is a string of characters where any one of those
characters causes the line to be parsed into a separate arg at
that point. This can cause the line to be broken up into many
args, and each arg is stored in the REXX stem variable FILEARG.
So, the first parsed arg is in FILEARG.1, the second arg is
FILEARG.2, etc, and the number of args parsed is stored in
FILEARG.0. If rightseparators is a null string (ie, ""), then
that is the same as omitting the rightseparators arg.
leftseparators is a string of characters where any one of those
characters causes the line to be parsed into a separate arg at
that point. This can cause the line to be broken up into many
args, and each arg is stored in the REXX stem variable FILEARG.
The difference between rightseparators and leftseparators is
that the latter breaks off args from the end of the line,
whereas the former breaks off args from the front of the line.
So, the last parsed arg for leftseparators is placed in
FILEARG.1, the second to last arg is placed in FILEARG.2, etc,
and the number of args parsed is stored in FILEARG.0. If
leftseparators is a null string (ie, ""), then that is the same
as omitting the leftseparators arg. If both rightseparators and
leftseparators are specified, then the rightseparators args are
broken off first, and then leftseparators breaks args off of any
remaining text on the line.
Note: If rightseparators and/or leftseparators are omitted (or
both are null strings), then the line isn't broken up
into separate args (ie, it's returned as one string) and
FILEARG is not used.
Returns The return depends upon whether you are parsing the line into
separate args (ie, you have specified a string of separators),
or whether you are reading the line as one string.
For reading the line as one string:
If successful, the entire line contents are returned (ie, all
of the characters from the current position in the file up to
the newline character). The final newline and any line feeds
are stripped from the line. The REXX variable, FileErr is set
to the number of characters in the line, plus 1.
If an error or end of the file, a null string (ie, "") is
returned, and the REXX variable, FileErr is set to 0.
Note: A blank line in the file will return a null string, but FileErr=1.
For parsing the line into separate args:
If successful, each arg is returned in the REXX stem variable
FILEARG. So, the first parsed arg is in FILEARG.1, the second
arg is FILEARG.2, etc. The number of args parsed is stored in
FILEARG.0.
If an error or end of the file, the REXX stem variable
FILEARG.0 is set to 0.
Note: A blank line in the file will return FileArg.0=1 and FileArg.1="".
Examples /* Open 'myfile' for reading */
handle = FileOpen('myfile')
IF handle <> 0 THEN DO
/* Read the next line and print it. If no more lines, exit
*/
contents = FileGets(handle)
IF FileErr = 0 THEN LEAVE
SAY contents
END
err = FileClose(handle)
/* Open 'myfile' for reading */
handle = FileOpen('myfile')
linenum=1
IF handle <> 0 THEN DO
/* Read the next line, separating each arg by a blank space
between them. Also, trim leading and trailing spaces off
of each arg. Print the args. If no more lines, exit
*/
FileGets(handle, 't', ' ')
IF FileArg.0 = 0 THEN LEAVE
DO i = 1 to FileArg.0
SAY "line #"linenum": Arg #"i"="FileArg.i
END
linenum = linenum+1
END
err = FileClose(handle)
ΓòÉΓòÉΓòÉ 4.3.3. FileReadValue ΓòÉΓòÉΓòÉ
Syntax value = FileReadValue(handle, size, sign, Flags)
Purpose Reads in the next 1, 2, or 4 bytes (ie, 8-bit values) from an
open file/driver (depending upon whether size is 1, 2 or 4), and
returns a numeric value to the REXX script representing such.
This allows a REXX script to read binary CHAR, UCHAR, SHORT,
USHORT, LONG, and ULONG values from a file, and have them
returned in REXX form (ie, as a string of ascii digits
representing that number).
Note: This function can be used in combination with FileRead,
FileReadBlock, or FileGets upon the same handle.
Args handle is the opened handle as returned by FileOpen.
size is the size of the value to read; char, short, or long (ie,
1, 2, or 4). A char is 8-bits (ie, the next byte in the
file/driver). A short is 16-bits (ie, the next 2 bytes in the
file/driver). A long is 32-bits (ie, the next 4 bytes in the
file/driver). If this arg is not supplied, then char is
assumed.
sign determines whether the value is expressed as an unsigned
('+') or signed ('-') quantity. For unsigned char, the range is
0 to 255. For signed char, the range is -128 to 127. For
unsigned short, the range is 0 to 65,535. For signed short, the
range is -32,768 to 32,767. For unsigned long, the range is 0
to 4,294,947,295. For signed long, the range is -2,147,483,648
to 2,147,483,647. If sign is omitted, unsigned ('+') is
assumed.
Flags is any of the following:
'm' Read short or long values that are stored in Motorola
format (ie, MSB comes first, and LSB is last, versus Intel
format where LSB comes first, and MSB is last).
'h' Return the value expressed in hexadecimal format. A X
is not appended after the value, so it is up to your script to
convert the value to decimal using REXX's X2D is you wish to
perform any mathematical operations upon it. For example, if
you set this flag and read a USHORT hexidecimal value of F001,
'F001' is returned.
'b' Return the value expressed in binary format (ie, each
bit is its own digit; a 0 or 1). It is up to your script to
convert the value to decimal using REXX's B2X and X2D is you
wish to perform any mathematical operations upon it. For
example, if you set this flag and read a USHORT binary value of
0110 1111 0000 0001 (ie, hexadecimal 6F01), then
'0110111100000001' is returned.
If Flags is omitted, then it defaults to none of the above.
The order of Flags is irrelevant.
Returns If success, the binary char, short, or long, is read from the
file/driver and returned to the REXX script (ie, expressed as an
ascii string of digits -- the way that REXX internally expresses
numeric variables).
If an error or the end of file, a null string is returned.
Examples /* Open 'myfile' for reading */
handle = FileOpen('myfile')
IF handle <> 0 THEN DO
/* Read a signed char and print it */
contents = FileReadValue(handle, 1, '-')
IF contents <> "" THEN SAY contents
/* Read a signed short (Intel format) and print it */
contents = FileReadValue(handle, 2, '-')
IF contents <> "" THEN SAY contents
/* Read a unsigned short and print it */
contents = FileReadValue(handle, 2)
IF contents <> "" THEN SAY contents
/* Read an unsigned char and print it */
contents = FileReadValue(handle)
IF contents <> "" THEN SAY contents
/* Read a signed long and print it */
contents = FileReadValue(handle, 4, '-')
IF contents <> "" THEN SAY contents
/* Read an unsigned short (in Motorola format), expressed in
binary, and print it */
contents = FileReadValue(handle, 2, '+', 'mb')
IF contents <> "" THEN SAY contents
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.3.4. FileReadBlock ΓòÉΓòÉΓòÉ
Syntax contents = FileReadBlock(handle, variable count)
Purpose Reads in 8-bit characters from an open file or driver, converts
each byte to its REXX numeric value and stores that in the
specified stem variable. FileReadBlock is an alternative to
using FileRead for reading in numerous binary characters from a
file or driver which you want converted to REXX numeric values.
Note: This function can be used in combination with FileGets,
FileRead, or FileReadValue upon the same handle.
Args handle is the opened handle as returned by FileOpen.
variable is the name of the stem variable where you want the
values to be stored.
count is the number of 8-bit characters to read. If not
supplied, this defaults to 1 (ie, for reading the next character
in the file/driver).
Returns If success, the requested number of characters are read from the
file/driver, stored in the stem variable, and the total number
of values read is returned to the REXX script. Note that some
drivers may cause the REXX script to be suspended if the driver
doesn't have as many characters as you've requested, until such
time as the requested number of characters are received by the
driver (by its device). Other drivers may do some sort of
timeout if it is necessary to wait for more characters, after
which the driver will return however many characters it could
fill of your request. Furthermore, if you try to read more
characters from a file than are remaining in the file, you'll
only get as characters as are remaining. So, it's possible to
get less values back than you requested, including even 0, if
the end of file is reached, or if a driver has no characters
ready to be read, but doesn't suspend the REXX script waiting
for characters to be received.
If an error, a null string is returned. Also, some drivers that
have no characters ready to be read, but which don't suspend the
REXX script until the requested characters are received, may
return a null string.
Examples /* Open 'myfile' for reading */
handle = FileOpen('myfile')
IF handle <> 0 THEN DO
/* Read upto 10 values into BLORT.X and print them */
count = FileReadBlock(handle, 'blort', 10)
IF count <> "" THEN DO
DO i = 1 TO count
SAY blort.count
END
END
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.4. Write data to a File/Device ΓòÉΓòÉΓòÉ
These functions are used to write data to a file or device. You must open a
file/device with FileOpen before you use these functions. FileWrite is used to
write individual (8-bit) characters, or a specific number of characters to a
file/device. It's essentially an equivalent to CHAROUT. No translation is
performed upon the data. All REXX variables, even numeric ones, are stored
internally as ascii strings. So whatever you write to a file/device is seen by
the file system or device as ascii text. But if you need to write out binary
data (and most non-REXX programs and device drivers expect to deal with numeric
data in binary), you should use FileWriteValue. This automatically translates
some REXX numeric value to its respecitve binary LONG (32-bit value), SHORT
(16-bit value), or CHAR (8-bit) value, before writing it to disk or sending it
to a device. Finally, FilePuts is essentially an alternative to LINEOUT.
ΓòÉΓòÉΓòÉ 4.4.1. FileWrite ΓòÉΓòÉΓòÉ
Syntax actual = FileWrite(handle, contents, count)
Purpose Writes out characters (ie, 8-bit bytes) to an open file or
driver. No translation is performed upon the characters.
Remember that REXX internally stores all variables as ascii
strings, including numeric variables, so if you want to write
out binary values, use FileWriteValue instead. FileWrite is an
alternative to using CHAROUT for writing ascii text characters
to a file.
Note: This function can be used in combination with FilePuts or
FileWriteValue upon the same handle.
Args handle is the opened handle as returned by FileOpen.
contents is the string of characters to write to the
file/driver.
count is the number of bytes to write to the file/driver (ie,
number of characters in the passed contents). If not supplied,
this defaults to 1 (ie, for writing one passed character to the
file/driver).
Returns This returns the number of bytes (ie, characters) actually
written out. So, if successful, this will return the same value
as count.
If an error, it will return 0 or a mismatch with count.
Examples /* Open 'myfile' for writing */
handle = FileOpen('myfile', 'ws--', 'on')
IF handle <> 0 THEN DO
/* Write 10 characters (ie, 0123456789) */
err = FileWrite(handle, '0123456789', 10)
IF err <> 10 THEN SAY 'error'
/* Write 1 more character */
mychar = '*' /* Just for the hell of it, store in a variable
*/
err = FileWrite(handle, mychar)
IF err <> 1 THEN SAY 'error'
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.4.2. FilePuts ΓòÉΓòÉΓòÉ
Syntax actual = FilePuts(handle, line)
Purpose Writes out one line of text to an open file or driver. No
translation is done on any of the characters of the line (so
this should be used merely as an alternative to the standard
REXX command LINEOUT). There is no limit on the line length.
Note: This function can be used in combination with FileWrite
or FileWriteValue upon the same handle.
Args handle is the opened handle as returned by FileOpen.
line are the characters to write to the file/driver as a line of
text. FILEREXX automatically appends a line feed and newline
character to the end of the line written out.
Note: If no line arg is supplied (or a null string), then only
a line feed and newline character are written out. So,
this can be used to "close" a line after numerous calls
to FileWrite to write out separate characters of a line.
Returns If successful, this returns the number of characters written
out, including the line feed and newline characters appended to
the line.
If an error, it returns 0 or a mismatch with the number of
characters that you attempted to write (plus 2).
Examples /* Open 'myfile' for writing */
handle = FileOpen('myfile', 'ws--', 'on')
IF handle <> 0 THEN DO
/* Write the characters 0123456789 as a line */
err = FilePuts(handle, '0123456789')
IF err <> 12 THEN SAY 'error'
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.4.3. FileWriteValue ΓòÉΓòÉΓòÉ
Syntax actual = FileWriteValue(handle, values, size, Flags)
Purpose Writes out one or more numeric values as expressed by REXX (ie,
in the form of an ascii string of digits) to an open file or
driver as a binary char, short, or long (depending upon whether
size is 1, 2 or 4). This allows a REXX script to write binary
CHAR, UCHAR, SHORT, USHORT, LONG, and ULONG values to a
file/driver.
Note: This function can be used in combination with FileWrite
or FilePuts upon the same handle.
Args handle is the opened handle as returned by FileOpen.
values are the values that you wish to write out in binary. For
example, if you pass a value of 6, it gets written out as a six,
rather than as the ascii digit for six which is hex 36. You can
specify more than one value if desired. Simply leave a space
between each value. One caveat with negative numbers is that
the number must be enclosed within quotes if you specify it as a
literal string rather than a variable (or REXX will think that
you wish to subtract that value from the value preceding it).
You are limited to writing 64 values at a time if size is 4, 128
values if size is 2, or 256 values if size is 1.
size is the size of the value to write; char, short, or long
(ie, 1, 2, or 4). A char is 8-bits (ie, write 1 byte to the
file/driver). A short is 16-bits (ie, write 2 bytes to the
file). A long is 32-bits (ie, write 4 bytes to the file). If
this arg is not supplied, then char is assumed.
Flags is any of the following:
'm' Write short or long values in Motorola format (ie, MSB
comes first, and LSB is last, versus Intel format where LSB
comes first, and MSB is last). Of course, you always supply the
value in Intel format, but choosing Motorola format causes the
value to be converted to Motorola format when written to the
file.
'h' The value that you supplied is in hexadecimal format.
Do not put a X after the value. Simply express it in
hexidecimal. For example, if you wish to write out a USHORT
hexidecimal value of F001, then simply pass 'F001' and set this
flag.
'b' The value that you supplied is in binary format. For
example, if you wish to write out a UCHAR (ie, 8-bits) binary
value of 10001000 (ie, hexidecimal 88), then simply pass
'10001000' and set this flag.
If Flags is omitted, then it defaults to none of the above.
The order of Flags is irrelevant.
Returns This returns the number of bytes (ie, characters) actually
written out. So, if successful, this will return the same value
as size * the number of values that you specified.
If an error, it will return 0 or a mismatch with size * the
number of values that you specified.
Examples /* Open 'myfile' for writing */
handle = FileOpen('myfile', 'ws--', 'on')
IF handle <> 0 THEN DO
/* Write the value -30 as a char */
err = FileWriteValue(handle, -30, 1)
IF err <> 1 THEN SAY 'error'
/* Write the value -45 as a short */
myval = -45 /* Just for the hell of it, store in a variable
*/
err = FileWriteValue(handle, mychar, 2)
IF err <> 2 THEN SAY 'error'
/* Write the value 10000 as a long in Motorola format */
err = FileWriteValue(handle, 10000, 4, 'm')
IF err <> 4 THEN SAY 'error'
err = FileClose(handle)
END
This writes out 3 values with one call to FileWriteValue(). All
of the values must be the same size, and any negative values,
expressed as a literal string, must be enclosed in quotes. It's
more efficient to write out several values with one call to
FileWriteValue rather than a separate call for each value.
/* Open 'myfile' for writing */
handle = FileOpen('myfile', 'ws--', 'on')
IF handle <> 0 THEN DO
myval = -3 /* Just for the hell of it, store in a variable
*/
/* Write the values 4, -30, and -3 as chars */
err = FileWriteValue(handle, 4 '-30' myval, 1)
IF err <> 3 THEN SAY 'error' /* Note: size*number of values
written = 3 */
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.5. Setting/Querying the file position for read/write ΓòÉΓòÉΓòÉ
You must open a file/device with FileOpen before you use FileSeek. A file on
disk contains lots of "bytes" of information. You can skip around the file,
reading only certain data (ie, with FileRead, FileGets, or FileReadValue), and
skipping over other data by using FileSeek to do the skipping. Also, you can
use FileSeek to set a position where you wish to overwrite certain bytes (ie,
change the data to new values).
ΓòÉΓòÉΓòÉ 4.5.1. FileSeek ΓòÉΓòÉΓòÉ
Syntax newpos = FileSeek(handle, amount, origin)
Purpose This allows a script to skip over bytes or go back to bytes that
were already moved past. A subsequent FileRead, FileReadValue,
or FileGets will start reading at that position. A subsequent
FileWrite, FileWriteValue, or FilePuts will start writing at
that position. Note that specifying an amount of 0 and an
origin of 1 will return the current position without changing
that position.
Note: Many devices do not support the concept of "seek"ing, and
this function will always return an error from such a
device's driver.
Args handle is the opened handle as returned by FileOpen.
amount is the number of bytes to move forward or backward in the
file. A negative value moves backward, and a positive value
moves forward.
origin tells from where to start the move (ie, where to
reference your amount from). It can be one of the following:
0 Beginning of the file
1 Current position in the file
2 End of the file
If the origin arg is not supplied, the current position is
assumed to be the origin.
Returns If successful, this returns the new, "current file position"
which is the offset in bytes from the head (ie, start) of the
file (after the seek). (0 is the head of the file).
If an error, a null string is returned (ie, "").
Examples /* Open 'myfile' for writing and seek to the end of the file */
handle = FileOpen('myfile', 'ws--', 'on')
IF handle <> 0 THEN DO
err = FileSeek(handle, 0, 2)
IF err = "" THEN SAY 'error seeking'
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.6. Setup/Control a Device or query its settings ΓòÉΓòÉΓòÉ
You must open a device driver with FileOpen before you use this function. This
function allows you to send commands to the device driver to operate its
device. For certain commands, you may define a "request block" which sends
data to the device to control it or receives data back from a device that
indicates something about its operation. Each device driver gets to define
what commands it supports and whatever request blocks are associated with those
commands, so you must consult the documentation for a device driver that you
wish to control. Nevertheless, IBM has established certain standardized "sets
of commands" for some devices. For example, nearly everyone who makes a driver
that controls a modem follows IBM's set of commands for the COM driver, such as
setting baud rate, setting handshaking, etc.
Typically, you'll open a device driver by passing the driver name to FileOpen.
Then, you'll use FileDevIOCtl to setup or obtain information about the device
associated with that driver. Then, you'll use FileWriteValue (or FileWrite or
FilePuts if the device expects ascii data, such as a modem) to send data to
that device, and FileReadValue (or FileRead or FileGets to receive data from
the device. When done, you'll close the driver with FileClose.
ΓòÉΓòÉΓòÉ 4.6.1. FileDevIOCtl ΓòÉΓòÉΓòÉ
Syntax error = FileDevIOCtl(handle, catagory, function, paramvar,
datavar, Flags)
Purpose Lets a REXX script perform operations specific to a particular
device, such as setting the baud rate of a modem.
Args handle is the opened handle as returned by FileOpen.
catagory is the catagory number for the IOCTL. For example, the
functions for an ASYNC RS232-C Control driver (ie, COM driver)
all come under catagory number 1. Check the literature for the
device driver (ie, under the section that describes its IOCTL
interface -- how OS/2's DosDevIOCtl() is used with it) for the
catagory numbers that the driver supports. IBM's book Physical
Device Driver Reference lists IOCTL interfaces for standard
drivers such as COM, KEYBOARD, MOUSE, etc.
Note: The catagory must be expressed in decimal, not hexadecimal.
If the catagory arg is omitted, it defaults to 128 (80 hex),
which is typically used for driver specific catagories.
function is the function number for the IOCTL. For example, if
you want to set the bit rate of an ASYNC RS232-C Control driver
(ie, COM driver), then this is function 65. Check the
literature for the device driver for the function numbers that
the driver supports.
Note: The function must be expressed in decimal, not hexadecimal.
paramvar is the REXX stem variable name that describes and
initializes any Parameters Block sent to the driver. It also
describes any Parameters Block that will be received from the
driver, and the returned values are placed into this REXX stem
variable. If this arg is omitted, then no Parameter Block is
sent to nor received from the driver. For example, if you want
to set the bit rate (ie, Catagory 1, Function 65) of an ASYNC
RS232-C Control driver (ie, COM driver), then you must describe
and initialize a Parameters Block that contains the desired bit
rate.
datavar is the REXX stem variable name that describes and
initializes any Data Block sent to the driver. It also
describes any Data Block that will be received from the driver,
and the returned values are placed into this REXX stem variable.
If this arg is omitted, then no Data Block is sent to nor
received from the driver. For example, if you want to find out
the bit rate (ie, Catagory 1, Function 97) of an ASYNC RS232-C
Control driver (ie, COM driver), then you must describe a Data
Block so that the driver can return its current bit rate.
Flags is any of the following:
'p' The Parameters Block returned by the driver is to be
copied into the REXX stem variable that described that Block.
'd' The Data Block returned by the driver is to be copied
into the REXX stem variable that described that Block.
Returns If successful, a 0 is returned. Also, FILEREXX may fill in the
REXX stem variables for the Parameters and/or Data Block if the
appropriate Flags were set to have the driver return those
Blocks.
If an error, a non-zero number is returned, which represents the
error number from the driver, or REXX, or FILEREXX. Here are
some possible error numbers, and their meanings:
1 Invalid Function (driver doesn't support that function
number)
6 Invalid (non-zero) Handle
15 Invalid drive specified to a driver
31 General driver failure (could be lots of reasons why)
87 Invalid parameter (ie, the Data or Parameters Block was
described incorrectly)
111 Buffer overflow in the driver
115 Protection violation in the driver
117 Invalid Catagory (driver doesn't support that catagory
number)
119 Bad driver level (ie, need an updated version of the
driver)
163 Uncertain media (driver having trouble accessing its
device)
165 Monitors not supported
-1 Rexx Variable (for Parameters or Data Block) can't be
found. (Check that you spelled it correctly, and got all of stem
numbers in order)
-2 More values/fields than specified Block size
-3 Out of memory for Parameters or Data Block
-4 Truncation occurred. Your description/initialization for
a field was longer than 255 characters.
-8 Invalid REXX variable name
-16 Out of memory for REXX variables
Discussion FileDevIOCtl() is passed the name of the REXX stem variable that
describes the (Parameters or Data) Block sent to or received
from the driver. For example, you may pass 'REQUEST' as the
name of the REXX variable that describes the Parameters Block.
When describing a Block, you need to know how many total bytes
(ie, 8-bit characters) are in the Block. This is the size of
the Block. You set the first stem variable (ie, with an
extension of 0) to this number. For example, assume that our
Block will have a size of 16. Then, REQUEST.0 = 16.
Variables with extensions of .1 and more describe each "field"
of the Block. For example, REQUEST.1 would describe the first
field. REQUEST.2 would describe the second field. Etc.
Each field can contain one or more values. A field begins with
a "Type". This is a 1, 2, 4, -1, -2, or -4 to indicate whether
the field's value(s) are expressed as unsigned char (8-bits),
unsigned short (16-bits), unsigned long (32-bits), signed char
(8-bits), signed short (16-bits), or signed long (32-bits)
value(s) respectively. Then the field's value(s) follow. If
the "Type" is 0, then the value string is used verbatim without
any translation to binary values. The Type can have an
extension, which I'll refer to as the "Count". This will be how
many values of that type follow. If the Count arg is omitted,
then the field's size is ultimately determined by however many
values follow. For example, if you had a field that consisted
of 32 unsigned chars, you could define the Type and Count as
1.32 and then list the 32 values after that. If you don't
supply as many values as "Count", then null bytes are used to
pad out to Count. There can be an additional extension after
the Count, which I'll refer to as an "Initialization". This
will be either a numeric value that it is to be duplicated for
Count times, or a (non-numeric) character that it is to be
duplicated Count times. For example, if you wanted to specify
32 unsigned chars and set them all to the value 16, the Type,
Count, and Initialization would be 1.32.16 with no need to
specify any values after that. If you wanted to specify 4 'A'
chars, the Type, Count, and Initialization would be 0.4.A with
no need to specify any chars after that.
Placing a 'H' before a Type means that you're expressing the
values (or Initialization) in hexadecimal. Placing a 'B' before
a Type means that you're expressing the values in binary. This
is not applicable to Type 0.
Say that you want a block that is composed of 5 fields. The
first field is 1 unsigned char with a value of 16. The second
field is 3 signed shorts with the values -400, 20, and 0. The
third field is the string "Hello". The fourth field is 4 signed
chars with the values 1 2 0 0. The fifth field will be 6
unsigned chars, initialized to 0. Here's an example of that:
/* Size of REQUEST block. Add up the absolute value of each
field's Types (multipled by any Counts, or by the number of
values supplied if no Count). For a Type of 0 (String), simply
add Count, or the number of values specified. So, for this
Block's 4 fields, we have (1*1)+(2*3)+5+(1*4)+(1*6) */
REQUEST.0 = 22
/* First field of REQUEST. Unsigned char. Value is 16 */
REQUEST.1 = '1 16'
/* Second field of REQUEST. Signed short. There are 3 Values of
-400, 20, and 0 */
REQUEST.2 = '-2 -400 20 0'
/* Third field of REQUEST. A string */
REQUEST.3 = '0 Hello'
/* Fourth field of REQUEST. Signed char. Count is 4 (although
only the first two values are supplied) */
REQUEST.4 = '-1.4 1 2'
/* Fifth field of REQUEST. Unsigned char. Count is 6.
Initialization is 0 */
REQUEST.5 = '1.6.0'
It's also permissible to have more than one Type, Count, and
values (or Initialization) per field. But, all of the Types
must also have a Count, except for the last Type (which may or
may not have a Count). For example, say that you want to make
"Hello" a null-terminated string:
REQUEST.3 = '0.5 Hello 1 0'
When you're describing a Block which is going to be filled in by
the driver and returned to your script, you don't need to
initialize the fields as long as you provide Counts for each
Type. For example, the above Block would be described as so:
/* Size of REQUEST block. Add up the absolute value of each
field's Types (multipled by any Counts, or by the number of
values supplied if no Count). For a Type of 0 (String), simply
add Count, or the number of values specified. So, for this
Block's 4 fields, we have (1*1)+(2*3)+5+(1*4)+(1*6) */
REQUEST.0 = 22
/* First field of REQUEST. 1 unsigned char */
REQUEST.1 = '1.1'
/* Second field of REQUEST. 3 signed shorts */
REQUEST.2 = '-2.3'
/* Third field of REQUEST. A string of 5 characters */
REQUEST.3 = '0.5'
/* Fourth field of REQUEST. 4 signed chars */
REQUEST.4 = '-1.4'
/* Fifth field of REQUEST. 6 unsigned chars */
REQUEST.5 = '1.6'
The driver returns the values for the respective fields in those
same REXX variables. For example, let's say that the driver is
going to return the values 30, 4, and -6 for the second field.
It would set REQUEST.2 to the string '30 4 -6'. You would need
to parse this variable to extract the individual values (which
is why it's better to only have one value per field -- then the
variable ends up being set to that one value, and there's no
need for any parsing).
Of course, if the driver wanted a fully initialized Block
despite the fact that it may also be returning new values for
the Block, you would then initialize it as in the first example.
Remember to set the Flags arg to 'p' if the driver is to return
a filled-in Parameters Block. Set the Flags arg to 'd' if the
driver is to return a filled-in Data Block. Set the Flags arg
to 'pd' if the driver is to return filled-in Parameters and Data
Blocks.
Say that you wanted to describe a field that contained an 8-bit
char, but you wish to express it in binary (ie, each bit is a 0
or 1) rather than decimal or hexadecimal. Let's say that the
bits 0 to 3, and bit 7 are going to be set (ie, 1) and the
remaining bits are going to be clear (ie, 0).
REQUEST.1 = 'B1 10000111'
Say that you wanted to describe that same field expressed in
hexadecimal. That would be 87.
REQUEST.1 = 'H1 87'
If you mix different Types in a field, and the driver is
returning a filled in Block, the driver returns the field with
all values set to the last Type of that field. For example, say
that you initialized that null-terminated string as so:
REQUEST.1 = '0.5 Hello 1 0'
When the driver returns the Block, it would set this field to 6
numeric values (ie, unsigned char). For example, if it returned
the same value(s), you would see each character of "Hello"
expressed as an ascii value. The result would be '72 101 108
108 111 0'.
Note: Never describe a field to be returned that will result in
a line length greater than 255 characters. This is no
problem if each field only contains one value, or a (Type
0) string that is less than 255 characters.
A field that contains a pointer (ie, a field that points to some
memory area) can't be initialized (although you could declare it
as an unsigned long and set it to 0 perhaps). Because IBM's
Device Driver Team simply haven't gotten on the 32-bit bandwagon
like the rest of OS/2's developers, and created a new 32-bit PDD
model that standardized on all addresses expressed as 0:32
(instead of the current mixture of 16:16 and 0:32), it's simply
not worth having FileDevIOCtl() try to hassle with setting up
various types of pointers. Scream at IBM if you want 32-bit
PDDs.
Examples See com.cmd
ΓòÉΓòÉΓòÉ 4.7. Querying information about a File/Device ΓòÉΓòÉΓòÉ
You must open a file/device with FileOpen before you use these functions. They
are used to obtain information about files such as the file size, the date that
it was last modified, and its attributes (ie, is it read-only, or hidden, or a
system file, etc). You can also use FileGetInfo to get information about a
device if the handle (returned by FileOpen) is for some device driver.
ΓòÉΓòÉΓòÉ 4.7.1. FileGetInfo ΓòÉΓòÉΓòÉ
Syntax err = FileGetInfo(filehandle, VarName, infotype)
Purpose Lets a REXX script get information about an open file, such as
its size, last write date and time (ie, date and time that it
was last modified), size of its extended attributes, and its
attribute bits.
Note: Many devices do not support the concept of a "size", and
this function will always return an error from such a
device's driver.
Args handle is the opened handle as returned by FileOpen.
VarName is the REXX stem variable where info is returned. The
file's size is returned in the variable name with a .0
extension. If a directory, then the size is a null string. The
Last Write Date/Time is returned in the variable name with a .1
extension. The month, day, and year are first, each separated
by a space, then the hour, minute, and second follow. The hour
goes from 1 to 24, where 13 to 24 are for 1PM to 12PM. The file
attributes are returned in the variable name with a .2
extension. This is expressed in binary (ie, 32 numeric digits,
where each digit is a 0 or 1, meaning that the respective bit is
clear or set). The first bit (ie, rightmost digit) is a 1 if
the file is read-only. The second bit is a 1 if the file is
hidden. The third bit is a 1 if the file is a system file. The
fifth bit is a 1 if you're dealing with a directory rather than
a file. The sixth bit is a 1 if the file is archived. The
extended attributes size is returned in the variable name with a
.3 extension. Note that the return is twice what the size
really is, and reflects how much memory would be needed to load
the EA. The file's Type is returned in the variable name with a
.4 extension (see below under TYPE flag).
infotype determines which information you want returned, and can
be any of the following, each separated by a | character, and
all enclosed in quotes:
SIZE Return file/dir size (size for a dir is always a null
string)
DATE Return last written date and time
ATTR Return attribute bits
EASIZE Return size of extended attributes
TYPE Return a string that contains several numbers
identifying the type of file. The first number is 0 if the file
is local; otherwise 1 if the file is on a remote server. The
second number is 0 if this is a file, 1 is this is a driver (ie,
device), or 2 if this is a pipe. The third number will only be
present if you're dealing with a local driver. This will be
expressed as a 32-bit (ie, 32 digits, with each digit being 0 or
1) value, and represents the driver's attributes word. If
you're dealing with a driver, then the returned size, EA size,
and attribute bits will all be zero, and the file date will be
'0 0 1980 0 0 0'.
If infotype is omitted, only SIZE information is returned. The
order of infotype parameters is irrelevant.
Returns If successful, a 0 is returned. Also, FILEREXX may fill in the
REXX stem variables described above.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
5 Access denied
6 Invalid handle
111 Buffer overflow
124 Invalid level
130 Direct access handle
254 Invalid EA name
255 EA list inconsistent
1 Rexx Variable (for VarName) can't be found. (Check that
you spelled it correctly)
4 Truncation occurred
8 Invalid REXX variable name
16 Out of memory for returning REXX variables
Examples /* Open 'myfile' for reading and get its size and attribute bits
*/
handle = FileOpen('myfile', 'r', 'e')
IF handle <> 0 THEN DO
err = FileGetInfo(handle, 'Info', 'SIZE|ATTR')
IF err = 0 THEN DO
SAY 'size of file =' Info.0 'bytes'
SAY 'file attribute bits =' Info.2
END
err = FileClose(handle)
END
ΓòÉΓòÉΓòÉ 4.8. Delete/Copy/Move Files ΓòÉΓòÉΓòÉ
These functions can work on just one file, or because they support wildcards,
can be used to copy, move, or delete groups of files.
ΓòÉΓòÉΓòÉ 4.8.1. FileDeleteFile ΓòÉΓòÉΓòÉ
Syntax err = FileDeleteFile(filename)
Purpose Deletes a file (or multiple files if wildcards are used in
filename).
Args filename is the name of the file(s) to delete. This can be
fully qualified with a drive and path. If filename is omitted,
"*.*" is assumed (ie, delete all files in the current
directory). FileDeleteFile does not delete directories. You
need to use FileRmDir to delete a directory.
The wildcards * and ? can be used when specifying the filename.
This makes it possible to delete more than one file with a
single call to FileDeleteFile(). * matches any amount of
characters up to a .. ? matches any one character, except for
..
When the filename is a directory (as opposed to a single file),
you must end the arg with a \ character, or \*.*, or some other
string containing wildcards.
Note: FileDeleteFile is not recursive. That is, it won't
delete the files in any subdirectories that match some
wildcard pattern. For example, even if you specify *.*
as the source string, FileDeleteFile won't delete the
contents of any subdirectories within the current
directory (nor the contents of any subdirectories inside
of those subdirectories). If you want recursive action,
you have to use FileDeleteFile to get a listing of all of
the directories (ie, Flags = DIRONLY) in the desired
directory, and then do a FileDeleteFile on each
subdirectory. You'll also have to use FileMatchFile on
each subdirectory to see if it has subdirectories too.
Finally, you'll have to use FileRmDir to remove the directories.
Returns If successful, a 0 is returned.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
2 File not found
3 Path not found
5 Access denied
26 Not DOS disk
32 Sharing violation
36 Sharing buffer exceeded
87 Invalid parameter
108 Drive locked
111 Buffer overflow
112 Destination disk is full
113 No more search handles. Perhaps too many nested calls to
FileMatchFile() while doing this FileDeleteFile() FileMatchFile
with a 0 for the VarName arg.
206 Filename exceeded character limit
208 Meta expansion too long
Examples /* Delete 'myfile' */
err = FileDeleteFile('myfile')
IF err = 0 THEN SAY 'File is deleted'
/* Delete all files in C:\temp */
err = FileDeleteFile('C:\temp\')
IF err = 0 THEN SAY 'Files are deleted'
/* Delete all files in C:\temp that end in with a .bak extension
*/
err = FileDeleteFile('C:\temp\*.bak')
IF err = 0 THEN SAY 'Files are deleted'
ΓòÉΓòÉΓòÉ 4.8.2. FileMoveFile ΓòÉΓòÉΓòÉ
Syntax err = FileMoveFile(source, destination)
Purpose Moves and/or renames a file (or multiple files if wildcards are
used in the source and destination).
Args source is the name of the file(s) to move. This can be fully
qualified with a drive and path. If source is omitted, "*.*" is
assumed (ie, move all files in the current directory).
destination is the new name and/or destination for the file(s).
This can be fully qualified with a drive and path, as well as a
new name for the file(s). If destination points to a drive or
directory, then the file is moved to that directory or drive
(which must already exist -- FileMoveFile does not create new
directories) with the same name. If destination is omitted,
"*.*" is assumed (ie, move all source files to the current
directory).
A file can be moved across devices, as long as you specify the
drive for both the source and destination.
When the source or destination is a directory (as opposed to a
single file), you must end the arg with a \ character, or \*.*,
or some other string containing wildcards.
The wildcards * and ? can be used when specifying the source or
destination. This makes it possible to move more than one file
with a single call to FileMoveFile(), and also give the files
new names. * matches any amount of characters up to a .. ?
matches any one character, except for ..
Note: FileMoveFile is not recursive. That is, it won't move
the files in any subdirectories that match some wildcard
pattern. For example, even if you specify *.* as the
source string, FileMoveFile won't move the contents of
any subdirectories within the current directory (nor the
contents of any subdirectories inside of those
subdirectories). If you want recursive action, you have
to use FileMatchFile to get a listing of all of the
directories (ie, Flags = DIRONLY) in the desired
directory, and then do a FileMoveFile on each
subdirectory. You'll also have to use FileMatchFile on
each subdirectory to see if it has subdirectories too.
Returns If successful, a 0 is returned.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
2 File (ie, source) not found
3 Path not found
5 Access denied
17 Not same device. (Use FileCopyFile and FileDeleteFile
instead)
26 Not DOS disk
32 Sharing violation
36 Sharing buffer exceeded
87 Invalid parameter
108 Drive locked
112 Destination disk is full
206 Filename exceeded character limit
250 Circularity requested
251 Directory in cds
267 Directory error
282 EAs not supported on destination
283 Need EAs found
Examples /* Move 'myfile' to 'mydir' */
err = FileMoveFile('myfile', 'mydir\')
IF err = 0 THEN SAY 'File is moved'
/* Move 'myfile' to 'mydir', renaming it to myfile2 */
err = FileMoveFile('myfile', 'mydir\myfile2')
IF err = 0 THEN SAY 'File is moved and renamed'
/* Move 'myfile.c' in the C:\OS2 directory to 'mydir', renaming
it with a .bak extension */
err = FileMoveFile('C:\os2\myfile.c', 'mydir\*.bak')
IF err = 0 THEN SAY 'File is moved and renamed'
/* Move all files in 'mydir' to 'C:\' */
err = FileMoveFile('mydir\', 'C:\')
IF err = 0 THEN SAY 'Files are moved'
/* Move all files in 'mydir' that end in .cmd to 'C:\' */
err = FileMoveFile('mydir\*.cmd', 'C:\')
IF err = 0 THEN SAY 'Files are moved'
/* Move all files in the current directory that end in .cmd to
'C:\' */
err = FileMoveFile('*.cmd', 'C:\')
IF err = 0 THEN SAY 'Files are moved'
/* Move all files in 'mydir' to the current directory */
err = FileMoveFile('mydir\')
IF err = 0 THEN SAY 'Files are moved'
/* Move all files in 'mydir' to the current directory, renaming
them with a .bak extension */
err = FileMoveFile('mydir\', '*.bak')
IF err = 0 THEN SAY 'Files are moved'
/* Move all files in 'mydir' that have a .c extension to the
C:\OS2 directory, renaming them with a .bak extension */
err = FileMoveFile('MYDIR\*.C', 'c:\OS2\*.bak')
IF err = 0 THEN SAY 'Files are moved'
ΓòÉΓòÉΓòÉ 4.8.3. FileCopyFile ΓòÉΓòÉΓòÉ
Syntax err = FileCopyFile(source, destination, Flags)
Purpose Copies a file (or multiple files if wildcards are used in the
source and destination).
Args source is the name of the file(s) to copy. This can be fully
qualified with a drive and path. If source is omitted, "*.*" is
assumed (ie, copy all files in the current directory).
destination is the new name and/or destination for the file(s).
This can be fully qualified with a drive and path, as well as a
new name for the file(s). If destination points to a drive or
directory, then the file is copied to that directory or drive
(which must already exist -- FileCopyFile does not create new
directories) with the same name, perhaps overwriting any
previous file with that name (depending upon the REPLACE flag).
If destination is omitted, "*.*" is assumed (ie, copy all files
to the current directory).
The wildcards * and ? can be used when specifying the source or
destination. This makes it possible to copy more than one file
with a single call to FileCopyFile(), and also give the files
new names. * matches any amount of characters up to a .. ?
matches any one character, except for ..
When the source is a directory (as opposed to a single file),
you must end the arg with a \ character, or \*.*, or some other
string containing wildcards. Unlike with FileMoveFile(), if the
destination is a directory, you don't need to end it with a \
(although you can).
Flags can be any of the following, each separated by a |
character, and all enclosed in quotes:
REPLACE If there is already a destination file with the same
name existing, overwrite it.
APPEND Append source file to the end of destination file.
FAILEA If source has Extended Attributes, and if the
destination's media doesn't support EA's, then fail.
If Flags is omitted, it defaults to none of the above. The
order of Flags is irrelevant.
Note: FileCopyFile is not recursive. That is, it won't copy
the files in any subdirectories that match some wildcard
pattern. For example, even if you specify *.* as the
source string, FileCopyFile won't copy the contents of
any subdirectories within the current directory (nor the
contents of any subdirectories inside of those
subdirectories). If you want recursive action, you have
to use FileMatchFile to get a listing of all of the
directories (ie, Flags = DIRONLY) in the desired
directory, and then do a FileCopyFile on each
subdirectory. You'll also have to use FileMatchFile on
each subdirectory to see if it has subdirectories too.
Returns If successful, a 0 is returned.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
2 File (ie, source) not found
3 Path not found
5 Access denied
26 Not DOS disk
32 Sharing violation
36 Sharing buffer exceeded
87 Invalid parameter
108 Drive locked
112 Destination disk is full
206 Filename exceeded character limit
267 Directory error
282 EAs not supported on destination
283 Need EAs found
Examples /* Copy 'myfile' to c:\mydir\myfile2 */
err = FileCopyFile('myfile', 'c:\mydir\myfile2')
IF err = 0 THEN SAY 'File is copied'
/* Copy all .exe files in C:\OS2 dir to C:\MYDIR, replacing any
files with the same names */
err = FileCopyFile('C:\OS2\*.exe', 'c:\mydir', "REPLACE')
IF err = 0 THEN SAY 'Files are copied'
Also look at the examples for FileMoveFile(). The way that you
specify the source and destination are applicable to
FileCopyFile().
ΓòÉΓòÉΓòÉ 4.9. Create/Delete Directories ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 4.9.1. FileMkDir ΓòÉΓòÉΓòÉ
Syntax err = FileMkDir(dirname)
Purpose Creates a directory.
Args dirname is the name of the directory to create.
Returns If successful, a 0 is returned.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
3 Path not found
5 Access denied
26 Not DOS disk
87 Invalid parameter
108 Drive locked
206 Filename exceeded character limit
254 Invalid EA name
255 EA list inconsistent
Examples /* Create C:\temp */
err = FileMkDir('C:\temp')
IF err = 0 THEN SAY "Created it"
ΓòÉΓòÉΓòÉ 4.9.2. FileRmDir ΓòÉΓòÉΓòÉ
Syntax err = FileRmDir(dirname)
Purpose Deletes a directory.
Args dirname is the name of the directory to delete. The directory
must be empty; that is, it cannot have hidden files nor
directory entries other than the "." and ".." entries. To
delete files, use FileDeleteFile. The root directory and
current directory cannot be deleted. (To delete the current
directory, change to another directory using REXX's DIRECTORY
command, and then call FileRmDir).
Returns If successful, a 0 is returned.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
2 File not found
3 Path not found
5 Access denied
6 Invalid handle
16 Current directory. Change your directory, and then delete
it.
26 Not DOS disk
87 Invalid parameter
108 Drive locked
206 Filename exceeded character limit
Examples /* Delete C:\temp */
err = FileRmDir('C:\temp')
IF err = 0 THEN SAY "Deleted it"
ΓòÉΓòÉΓòÉ 4.10. List/Search Files/Directories ΓòÉΓòÉΓòÉ
FileMatchFile is used to list all of the filenames and/or subdirectories in a
specific directory (and obtain information about each file and subdirectory).
FileSearchPath can be used to locate a specific file or directory. It also can
be used to obtain the value of an environment variable (typically used to set
default paths).
ΓòÉΓòÉΓòÉ 4.10.1. FileMatchFile ΓòÉΓòÉΓòÉ
Syntax err = FileMatchFile(VarName, handle, pattern, attributes,
infotype)
Purpose To find the first/next file in the specified directory that
matches the specified pattern. FileMatchFile may be called many
times in a row to enumerate each matching item. Each time that
FileMatchFile is called, it either matches one more item, or
indicates that there are no more matching items. FileMatchFile
should either be called until it finds no more matches, or you
should make a call to specifically abort the search.
Args VarName is the name of the REXX stem variable where info is
returned. If you pass a 0 instead, then you are indicating that
you want to abort a search in progress and close the handle.
handle is the name of the REXX stem variable where FileMatchFile
returns the handle that you use on subsequent calls to
FileMatchFile. Before calling FileMatchFile for the first time,
you should initialize this variable to zero. After each call to
FileMatchFile, you'll check this variable. As long as it's not
zero, FileMatchFile has returned another match. When
FileMatchFile can't find any more matching items, it
automatically sets this variable to 0. (Also, FileMatchFile
returns error number 18 when it can't find any more matches).
pattern is the FileSpec to match. This can be fully qualified
with the drive and path. The wildcards * and ? can be used. *
matches any amount of characters up to a \, :, or .. ? matches
any one character. If pattern is omitted, "*.*" is assumed (ie,
search the current directory).
attributes determines which files/dirs are scanned and which are
skipped. It can be any of the following, each separated by a |
character, and all enclosed in quotes:
RDO include readonly files
RDOONLY only readonly (exclude everything else)
HID include hidden files
HIDONLY only hidden files (exclude everything else)
SYS include system files
SYSONLY only system files (exclude everything else)
DIR include subdirectories (ie, but not the contents of
such)
DIRONLY only directories (exclude everything else)
ARC include files with archive bit set
ARCONLY only files with archive bit set (exclude everything
else)
If attributes is omitted, it defaults to none of the above (ie,
matches only files that are read/write). The order of match
parameters is irrelevant.
infotype determines what info is returned along with the name of
the matching file/dir. It can be any of the following, each
separated by a | character, and all enclosed in quotes:
SIZE Return file/dir size (size for a dir is always a null
string)
DATE Return last written date and time
ATTR Return attribute bits
If infotype is omitted, it defaults to none of the above (ie,
only returns file/dir name). The order of infotype parameters
is irrelevant.
Returns If a match is found, a 0 is returned. Also, the name of the
matching file/dir is returned in your specified VarName. The
size is returned in the variable name with a .0 extension. If a
directory, then the size is a null string. The Last Write
Date/Time is returned in the variable name with a .1 extension.
The month, day, and year are first, each separated by a space,
then the hour, minute, and second follow. The hour goes from 1
to 24, where 13 to 24 are for 1PM to 12PM. The file attributes
are returned in the variable name with a .2 extension. This is
expressed in binary (ie, 32 numeric digits, where each digit is
a 0 or 1, meaning that the respective bit is clear or set). The
first bit (ie, rightmost digit) is a 1 if the file is read-only.
The second bit is a 1 if the file is hidden. The third bit is a
1 if the file is a system file. The fifth bit is a 1 if you're
dealing with a directory rather than a file. The sixth bit is a
1 if the file is archived. The extended attributes size is
returned in the variable name with a . 3 extension. Note that
the return is twice what the size really is, and reflects how
much memory would be needed to load the EA. The file's Type is
returned in the variable name with a .4 extension.
When there are no more matching files/dirs, then FileMatchFile
sets your handle variable to 0, and also returns an error number
of 18.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
2 File not found (ie, can't locate the initial file,
Varname, that you supplied, assuming that it's not a directory).
3 Path not found (ie, a problem with Varname's path)
5 Access denied
6 Invalid handle
18 No more matching files found
26 Not DOS disk
32 Sharing violation
36 Sharing buffer exceeded
87 Invalid parameter
108 Drive locked
111 Buffer overflow
112 Destination disk is full
113 No more search handles. Make sure that you always call
FileMatchFile until your handle variable is 0, or call
FileMatchFile with a 0 for the VarName arg.
206 Filename exceeded character limit
208 Meta expansion too long
254 Invalid EA name
255 EA list inconsistent
275 EAs didn't fit
Examples /* Search for all matches to '*.cmd' in current directory. Only
check read/write files */
/* Initially set handle to 0 */
Handle = 0
DO UNTIL Handle = 0
err = FileMatchFile('File', 'Handle', '*.cmd',, 'SIZE|DATE')
/* No error? (ie, another match) */
IF err = 0 THEN DO
/* Print matching filename (and its size and date) */
SAY File '|' File.0 '|' File.1
END
/* An error occurred (unless it was "no more files" -- we
ignore that since it only means that our loop is going to end,
being that Handle is now 0) */
ELSE IF err <> 18 THEN SAY "FileMatchFile('File', 'Handle',
'*.cmd',, 'SIZE|DATE') =" err
END
/* Collect all of the subdirectory names (and their attributes
bits) in the current directory. Note that we pass a variable
name of 'File.X' where the X is incremented. That means that the
first directory's name is stored in File.0 and its attributes
bits are stored in File.0.2. */
/* Initially set handle and count to 0 */
Handle = 0
Count = 0
DO UNTIL Handle = 0
err = FileMatchFile('File.'Count, 'Handle',, 'DIRONLY',
'ATTR')
/* No error? (ie, another match) */
IF err = 0 THEN DO
/* Increment Count */
Count = Count + 1
END
/* An error occurred? */
ELSE IF err <> 18 THEN SAY "Error collecting directories:"
err
If you wish to abort a loop in which you're making calls to
FileMatchFile (ie, you want to stop searching the directory
before you've exhausted all possible matches), you should make
sure that you call FileMatchFile one more time with a Varname
arg of 0, and passing Handle.
/* Initially set handle 0 */
Handle = 0
DO UNTIL Handle = 0
err = FileMatchFile('File', 'Handle', '*.exe')
/* No error? (ie, another match) */
IF err = 0 THEN DO
/* Let's say that you want to leave the loop right now.
First clean up with one more call to FileMatchFile */
CALL FileMatchFile(0,'Handle')
LEAVE
END
/* An error occurred? */
ELSE IF err <> 18 THEN SAY "Error:" err
Or, you could do the cleanup afterward, by checking Handle for
0.
/* Initially set handle to 0 */
Handle = 0
DO UNTIL Handle = 0
err = FileMatchFile('File', 'Handle', '*.exe')
/* No error? (ie, another match) */
IF err = 0 THEN DO
/* Let's say that you want to leave the loop right now */
LEAVE
END
/* An error occurred? */
ELSE IF err <> 18 THEN SAY "Error collecting directories:"
err
/* Do any cleanup now */
IF Handle <> 0 THEN CALL FileMatchFile(0,'Handle')
ΓòÉΓòÉΓòÉ 4.10.2. FileSearchPath ΓòÉΓòÉΓòÉ
Syntax FileSpec = FileSearchPath(path, filename)
Purpose Searches the specified path for the specified file/directory and
returns the full FileSpec of the file/dir if found. Also can be
used to get the value of an environment variable.
Args path is any environment variable that resembles a path, such as
'PATH', 'DPATH', etc.
filename is the file to search for within that path. The
wildcards * and ? can be used. * matches any amount of
characters up to a \, :, or .. ? matches any one character. If
wildcards are used, they appear in the returned FileSpec. If
the filename arg is not supplied, then the value of the
environment variable is returned. In this case, the environment
variable can be other than one assigned to some path.
Returns If successful, the full FileSpec is returned. If the filename
arg is not supplied, then the value of the environment variable
is returned.
If the file can't be found along the specified path, a null
string is returned.
Examples /* Search for a 'filerexx.dll' along LIBPATH */
name = FileSearchPath('LIBPATH', 'filerexx.dll')
/* found it? */
IF name <> '' THEN SAY "Found it"
/* Get the value of the environment variable VIDEO_DEVICES */
dev = FileSearchPath('VIDEO_DEVICES')
/* found it? */
IF dev <> '' THEN SAY "VIDEO_DEVICES =" dev
ΓòÉΓòÉΓòÉ 4.11. Query information about Drives/Devices ΓòÉΓòÉΓòÉ
FileDriveMap can list all of the drives on the system, as well as remote (ie,
LAN) drives. FileDevInfo can get information about a specific drive, such as
the total free space on it, its size, and the serial number and label of any
media in that drive. FileDevInfo can also be used to get the (internal) names
of drivers mounted upon the system, or check that a certain driver is mounted.
ΓòÉΓòÉΓòÉ 4.11.1. FileDriveMap ΓòÉΓòÉΓòÉ
Syntax map = FileDriveMap(startdrive, Flags)
Purpose Lists all of the drives with the specified attributes.
Args startdrive is the name of the drive at which to start listing.
For example, 'C:' skips the A and B drives. If startdrive is a
full FileSpec, the drive letter is extracted from it. If
startdrive is omitted, then the drives are listed from A.
Flags may be any one of the following, each separated by a |
character, and all enclosed in quotes:
FREE Lists drives which are free or not in use.
USED Lists drives which are accessible or in use. This
includes all local and remote drives.
LOCAL Lists only those drives which are local drives.
REMOTE Lists only those drives which are remote drives such
as redirected LAN resources, IFS attached drives, etc.
DETACHED Lists drives which are detached LAN resources.
NUMS Lists drives as numbers instead of letters, where '1'
is drive 'A'. For example, '1 2 3' is 'A:\ B:\ C:\'.
If Flags is omitted, it defaults to USED. The FREE flag is
mutually exclusive with the following 4, ie, if you set USED,
then it overrides FREE. The order of Flags is irrelevant.
Returns If successful, a string containing all of the drives with the
specified attributes is returned, each separated by a space.
For example, 'A:\ B:\ C:\'.
If an error (or no drives with those matching Flags are found),
a null string is returned.
Examples /* List all drives after C: */
map = FileDriveMap('C:\temp')
SAY map
ΓòÉΓòÉΓòÉ 4.11.2. FileDevInfo ΓòÉΓòÉΓòÉ
Syntax err = FileDevInfo(VarName, Device)
Purpose Gets information about a particular drive or device driver.
Args Device is either the name of the drive to query, for example,
'C:', or a device driver name to query, for example 'COM2', or
if a number is specified, then that driver is looked up in
OS/2's list of mounted drivers, for example, a 1 would return
information about the first mounted driver, and a 2 would return
information about the second mounted driver. If Device is a
drive, then you can specify a full filespec, for example,
'C:\OS2\DLL' would return info about C:. If Device is omitted,
then the current drive is queried.
VarName is the REXX stem variable where info is returned.
For a drive, the drive name (separated from any filespec, for
example, 'C:\OS2\DLL' returns 'C:\' and a \ character always
ends the drive name), is returned in the variable name without
any extension. If the Device arg was omitted, this will be the
current drive. 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.
For a device driver, it's name is returned in the variable name
without any extension. This will have the subdirectory '\DEV\'
prepended to the device's name. The driver's type is returned
in the variable name with a .0 extension. This will be 1 for a
Resident character device, a 2 for a Pseudocharacter device, a 3
for a Local Drive, or a 4 for a Remote drive attached to the
file-system driver. The variable name with a .1 extension will
always be a null string. This corresponds to the Drive Size
when querying a drive. Of course, a drive would never have a
null size, so you could use this variable when you aren't
certain if the Device arg that you're passing to FileDevInfo is
the name of a drive or a device driver.
Returns If successful, a 0 is returned. Also, FILEREXX will fill in the
REXX stem variables described above.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
15 Invalid drive
111 Buffer overflow
124 Invalid level
1 Rexx Variable (for VarName) can't be found. (Check that
you spelled it correctly)
4 Truncation occurred
8 Invalid REXX variable name
16 Out of memory for returning REXX variables
253 Device driver not found. The name that you supplied is not
a mounted driver.
259 No driver matching this number. The device driver number
that you supplied is greater than the number of drivers in the
list of mounted drivers.
Examples /* Get info about current drive */
err = FileDevInfo('Info')
IF err = 0 THEN DO
SAY 'Bytes Free =' Info.0
SAY 'Bytes Used =' Info.1
SAY 'Serial Number =' Info.2
SAY 'Volume Label =' Info.3
SAY 'Current drive =' Info
END
ELSE SAY "FileDevInfo('Info') =" err
/* List the names of all mounted device drivers */
drvnum = 1
err = 0
DO WHILE err = 0
/* Get the next driver in the list */
err = FileDevInfo('Info', drvnum)
IF err = 0 THEN DO
/* Chop off the \DEV\ subdirectory, and only display the
driver name */
err = FileGetPath('File', Info)
SAY File.2||File.3 END
drvnum = drvnum+1
END
IF err <> 259 THEN SAY "FileDevInfo('Info', drvnum) =" err
/* Check if COM2 driver is mounted */
err = FileDevInfo('Info', 'COM2')
IF err = 0 THEN SAY "COM2 is mounted."
ELSE IF err = 253 THEN SAY "COM2 is not mounted."
ELSE SAY "FileDevInfo('Info', 'COM2') =" err
ΓòÉΓòÉΓòÉ 4.12. Parse/Edit File/Directory/Drive names, Change/Query current Drive/Directory ΓòÉΓòÉΓòÉ
FileGetPath can split up a variable containing the full path name of some file
or directory into its separate components of drive, path (ie, parent
directories), file (or subdir) name, and extension. Also, it can be used to
obtain the name of the current drive and path (ie, directories). FileEditName
can be used to transform a file/directory name into a new name by using
wildcard pattern matching and replacing.
ΓòÉΓòÉΓòÉ 4.12.1. FileGetPath ΓòÉΓòÉΓòÉ
Syntax err = FileGetPath(VarName, FileSpec, Flags)
Purpose Splits the FileSpec into its separate components of drive, path
(ie, parent directories), file (or subdir) name, and extension.
It also can be used to obtain the current drive and path (split
into separate variables). It also can be used to change the
current drive and directory.
Args VarName is the REXX stem variable where info is returned. The
Drive is returned in the variable name with a .0 extension, for
example 'C:\'. This will be a null string if there was no drive
specified in the FileSpec. The Path (ie, parent directories) is
returned in the variable name with a .1 extension. This will be
a null string if there was no path specified in the FileSpec.
The Filename is returned in the variable with a .2 extension.
This will be a null string if the FileSpec arg is omitted. The
Extension is returned in the variable name with a .3 extension.
This will be a null string if there was no extension specified
in the FileSpec, or the FileSpec arg is omitted.
FileSpec is the full pathname to parse, for example,
'C:\os2\dll\pmwin.dll'. If FileSpec is omitted, then the
current drive and path are returned (and the Filename and
Extension variables are nulled). If FileSpec is only a drive
letter, then it need not have a \ at the end, for example, C: or
C:\ are both identical.
If the VarName arg is omitted, then the current drive and/or
directory is changed to the drive/directory specified FileSpec.
For example, 'C:\os2' changes the current drive to 'C:' and the
current directory to 'os2'. Passing 'os2\dll' would change the
current directory to '?:\os2\dll' where ? is whatever the
current drive already is (ie, the current drive isn't changed).
The FileSpec itself does not have to a directory. For example,
if you pass 'C:\os2\cmd.exe' and cmd.exe happens to be a file
(rather than a directory), the current drive is changed to 'C:'
and the current directory is changed to 'os2'.
Flags may be any one of the following, each separated by a |
character, and all enclosed in quotes:
CHK Check whether the FileSpec (if specified) is a directory
or file before parsing. For example, assume that you pass the
FileSpec 'C:\os2\dll'. Without the CHK flag, this would be
broken up with a drive of 'C:\', a directory of 'os2\', a
filename of 'dll', and a null string for extension. But if you
specify the CHK flag and dll happens to be a directory, then
this would be broken up with a drive of 'C:\', a directory of
'os2\dll\', and a null filename and extension. A way to force
FileGetPath to regard your FileSpec as pointing to a directory
rather than a file, is to make sure that the FileSpec ends with
a \. For example, even without the CHK flag, a FileSpec of
'C:\os2\dll\' would be broken up with a drive of 'C:\', a
directory of 'os2\dll\', and a null filename and extension.
If Flags is omitted, it defaults to none of the above. The
order of Flags is irrelevant.
Returns If successful, a 0 is returned. Also, FILEREXX will fill in the
REXX stem variables described above.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
2 File not found
3 Path not found
5 Access denied
8 Not enough memory
15 Invalid drive
26 Not DOS disk
87 Invalid parameter
108 Drive locked
111 Buffer overflow
206 Path name too long
1 Rexx Variable (for VarName) can't be found. (Check that
you spelled it correctly)
4 Truncation occurred
8 Invalid REXX variable name
16 Out of memory for returning REXX variables
Examples /* Get current drive and path */
err = FileGetPath('Info')
IF err = 0 THEN DO
SAY 'Current drive =' Info.0
SAY 'Current path =' Info.1
END
ELSE SAY "FileGetPath('Info') =" err
/* Split up 'C:\os2\dll\pmwin.dll' */
err = FileGetPath('Info', 'C:\os2\dll\pmwin.dll')
IF err = 0 THEN DO
SAY 'Drive =' Info.0
SAY 'Path =' Info.1
SAY 'Filename =' Info.2
SAY 'Extension =' Info.3
END
ELSE SAY "FileGetPath('Info', 'C:\os2\dll\pmwin.dll') =" err
/* Change current drive to C: and current directory to 'os2' */
err = FileGetPath(, 'C:\os2')
IF err = 0 THEN SAY 'Current directory and drive is changed'
ELSE SAY "FileGetPath(, 'C:\os2') =" err
ΓòÉΓòÉΓòÉ 4.12.2. FileEditName ΓòÉΓòÉΓòÉ
Syntax NewName = FileEditName(Source, Template, Flags)
Purpose Transforms a filename into a new name by applying a template
perhaps containing wildcard characters. FileEditName can be
used to easily resolve filenames 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. FileEditName will typically be used in
conjunction with FileMatchFile. FileMatchFile will be used to
search for "source files" (ie, to load and modify) and
FileEditName will be used to create new filenames based upon
those source names (ie, so that data can be saved in new files,
rather than overwriting the originals).
Args Source is the filename to be transformed. This can be fully
qualified with a drive and path (but doing so means that you'll
have to specify the USEDIR or SKIPDIR Flags). If this points to
a drive or directory, you should end the arg with a \ character
(unless you're transforming the name of a directory in order to
create a new directory name).
Template is the filename that is used to transform the Source
filename. This can be fully qualified with a drive and path
(but doing so means that you need to specify the RESTRICT,
SKIPDIR, and/or USEDIR Flags). If Template is omitted, "*.*" is
assumed (ie, the transformed name has the same filename and
extension pieces as the Source, although the drive and directory
may be different if you set the SKIPDIR flag). When the
Template is a directory (as opposed to a single file), you must
end the arg with a \ character, or \*.* (unless the source is
also a directory, and you wish to transform that directory
name). In this case, the transformed name
Flags is any of the following:
USEDIR Use any drive and directory of the source verbatim,
and ignore any drive and directory of the template.
SKIPDIR Ignore any drive and directory of the source, and
instead use any drive and directory on the template verbatim
(unless the RESTRICT flag is also set).
RESTRICT Ignore any drive and directory on the template.
If Flags is omitted, then it defaults to none of the above. In
this case, you should make sure that neither the Source nor
Template are fully qualified (ie, only the Filename and
Extension pieces are supplied).
The wildcards * and ? can be used when specifying the Template.
* matches any amount of characters in the Source up to a .. ?
matches any one character in the Source, except for ..
Returns If successful, the transformed name is returned.
If an error, a null string is returned. This will happen if the
Source and/or Template are fully qualified, but the proper Flags
aren't set to ignore the drive and directory of one while using
the other's drive and directory (or ignoring both args' drive
and directories by specifying both the SKIPDIR and RESTRICT
Flags).
Examples /* This creates a NewName of "hi" */
NewName = FileEditName('hello', 'hi')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "hello.exe" */
NewName = FileEditName('hello.cmd', '*.exe')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "hi.cmd" */
NewName = FileEditName('hello.cmd', 'hi.*')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "hello.cmd" */
NewName = FileEditName('hello.cmd', '*.*')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "c:\mydir\hello.bak" */
NewName = FileEditName('c:\mydir\hello.cmd', '*.bak', 'USEDIR')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "c:\hello.cmd" */
NewName = FileEditName('c:\mydir\hello.cmd', 'c:\', 'SKIPDIR')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "c:\hello2.cmd" */
NewName = FileEditName('mydir\mydir2\hello.cmd', 'c:\*2.*',
'SKIPDIR')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "hello.cmd" */
NewName = FileEditName('c:\mydir\hello.cmd', 'c:\',
'SKIPDIR|RESTRICT')
IF NewName = '' THEN SAY 'ERROR'
/* This creates a NewName of "c:\mydir\hi.bak" */
NewName = FileEditName('c:\mydir\', 'd:\mydir2\hi.bak',
'USEDIR')
IF NewName = '' THEN SAY 'ERROR'
ΓòÉΓòÉΓòÉ 4.13. FileSysInfo ΓòÉΓòÉΓòÉ
Syntax err = FileSysInfo(VarName, FirstItem, LastItem)
Purpose Gets information about the operating system.
Args VarName is the REXX stem variable where info is returned.
FirstItem is the item number of the first piece of information
that you desire. FirstItem is the item number of the last piece
of information that you desire. If you only want one piece of
information, simply omit the LastItem arg.
Each piece of information about the OS has a number associated
with it. Here are all of the numbers that you can specify, and
what piece of information each number returns.
0 Version number of FILEREXX (currently 1)
1 Maximum length, in bytes, of a path name.
2 Maximum number of text sessions.
3 Maximum number of PM sessions.
4 Maximum number of DOS sessions.
5 The drive from which the system was started (1 means drive
A, 2 means drive B, and so on).
6 Dynamic priority variation flag (0 means absolute priority,
1 means dynamic priority).
7 Maximum wait in seconds.
8 Minimum time slice in milliseconds.
9 Maximum time slice in milliseconds.
10 Memory page size in bytes. This value is 4096 for the
80386 processor.
11 Major OS version number.
12 Minor OS version number.
13 OS Revision letter.
14 Value of a 32-bit, free-running millisecond counter. This
value is zero when the system is started. This is useful as a
seed for a random number generator.
15 Low-order 32 bits of the time in seconds since January 1,
1970 at 0:00:00.
16 High-order 32 bits of the time in seconds since January 1,
1970 at 0:00:00.
17 Total number of bytes of physical memory in the system.
One page is 4KB.
18 Total number of bytes of resident memory in the system.
19 Maximum number of bytes of memory that can be allocated by
all processes in the system. This number is advisory and is not
guaranteed, since system conditions change constantly.
20 Maximum number of bytes of memory that this process can
allocate in its private arena. This number is advisory.
21 Maximum number of bytes of memory that a process can
allocate in the shared arena. This number is advisory.
22 Timer interval in tenths of a millisecond.
23 Maximum length, in bytes, of one component in a path name.
24 Session ID of the current foreground full-screen session.
Note that this only applies to full-screen sessions. The
Presentation Manager session (which displays Vio-windowed, PM,
and Windowed VDM sessions) is full-screen session ID 1.
25 Process ID of the current foreground process.
In order to obtain a piece of info, you pass the desired number
above as the FirstItem arg. The value of that item is returned
in the REXX variable with an extension that is the same as the
information number. For example, passing a FirstItem number of
5, and a VarName of 'Info' to FileSysInfo returns the drive
number from which the system was booted, in the REXX variable
Info.5.
You can obtain several pieces of information with one call by
supplying a LastItem arg. All of the pieces of info from the
FirstItem up to and including the last item are returned, in
their respective REXX variables.
If you omit the FirstItem arg, it defaults to 14 (ie, obtaining
the free-running counter value).
Returns If successful, a 0 is returned. Also, FILEREXX will fill in the
REXX stem variables described above.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX. Here are some possible
error numbers, and their meanings:
87 Invalid parameter. Don't specify an Item number of 0 or
greater than 25 (although future versions of the OS may support
item numbers greater than 25).
111 Buffer overflow
1 Rexx Variable (for VarName) can't be found. (Check that
you spelled it correctly)
4 Truncation occurred
8 Invalid REXX variable name
16 Out of memory for returning REXX variables
Examples /* Get the free running millisecond counter's value. Use it to
generate a random number from 0 to 2 (ie, 0, 1, or 2) */
err = FileSysInfo('Info')
IF err = 0 THEN SAY 'Random =' Info.14 // 3
ELSE SAY "FileSysInfo('Info') =" err
/* Get the OS major and minor version numbers, and revision
letter */
err = FileSysInfo('Info', 11, 13)
IF err = 0 THEN DO
SAY 'OS Version =' Info.11/10'.'Info.12
SAY 'OS Revision =' Info.13
END
ELSE SAY "FileSysInfo('Info', 11, 13) =" err
/* Get the total number of physical memory bytes */
err = FileSysInfo('Info', 17)
IF err = 0 THEN SAY "Total bytes =" Info.17
ELSE SAY "FileSysInfo('Info', 17) =" err
ΓòÉΓòÉΓòÉ 4.14. FileIterateExe ΓòÉΓòÉΓòÉ
Syntax err = FileIterateExe(program, source, destination, before,
after)
Purpose Calls another program a multiple number of times, passing it new
args each time. The source and destination filenames can
contain wildcards, and these are automatically resolved upon
each call to the other program. The net result is that
FileIterateExe can be used to specify filename args which
contain wildcards to programs that themselves can't deal with
wildcards. FileIterateExe implements a "filename global pattern
matching" frontend for any program that accepts a filename
argument.
Note: One limitation of FileIterateExe is that it can only
invoke a program that is the same type as the program
that launched your REXX script. For example, if you
launch your script from an OS/2 command prompt window,
that you can invoke windowed apps, but not a Presentation
Manager app. If your script was launched from PMREXX, or
my REXX Windowing Utility RX.EXE, or was launched by some
PM app, then you can invoke a PM program, but not an OS/2
full screen or windowed app.
Args program is the name of the program to run. This can be fully
qualified with a drive and path. You should also specify an
extension if the program has one (ie, .exe or .cmd). If program
is omitted, it defaults to the OS/2 command line shell. (This
is useful if you wish to execute built-in commands of the shell,
such as DIR. You'll omit the program arg, and pass 'DIR' as the
before arg).
source is the name of the file to supply as the source filename
to the program. This can be fully qualified with a drive and
path. If source is omitted, "*.*" is assumed (ie, invoke the
program upon each file in the current directory). When the
source is a directory (as opposed to a single file), you must
end the arg with a \ character, or \*.*. In this case, the
program is invoked upon all files in that directory.
FileIterateExe() never passes a program the name of any
directory, so it is only used for programs that operate upon
files, not directories themselves.
destination is the name of the file to supply as the destination
filename to the program. This can be fully qualified with a
drive and path, as well as a new name for the file(s). If
destination points to a drive or directory, then the source arg
is appended to that directory or drive name, and that becomes
the destination filename passed to the program. If you want the
exact same destination as source name, then pass '*.*' for the
destination arg. If the program doesn't require a destination
filename, or you don't wish to pass one, then omit the
destination arg.
The wildcards * and ? can be used when specifying the source or
destination. This makes it possible to invoke the program upon
more than one file with a single call to FileIterateExe(), and
also supply new names for destination files. * matches any
amount of characters up to a .. ? matches any one character,
except for ..
before is any string of characters that should be placed before
the source and destination filenames (ie, at the start of the
line) when the args are passed to the program upon each
invocation. Typically, these might be program "options" that
are required before any filenames.
after is any string of characters that should be placed after
the source and destination filenames (ie, at the end of the
line) when the args are passed to the program upon each
invocation. Typically, these might be program "options" that
are required after any filenames.
Note: FileIterateExe is not recursive. That is, it won't
invoke the program upon the files in any subdirectories
that match some wildcard pattern. For example, even if
you specify *.* as the source string, FileIterateExe
won't invoke the program upon the contents of any
subdirectories within the current directory (nor the
contents of any subdirectories inside of those
subdirectories). If you want recursive action, you have
to use FileMatchFile to get a listing of all of the
directories (ie, Flags = DIRONLY) in the desired
directory, and then do a FileIterateExe on each
subdirectory. You'll also have to use FileMatchFile on
each subdirectory to see if it has subdirectories too.
The source filename is always specified before the destination
filename when passed to the program. This means that programs
which require a source and destination filename must expect the
source first.
Returns If successful, a 0 is returned.
Note: In order for FileIterateExe to work properly, the program
must exit with a 0 for success. Otherwise, you'll get an
error back after the program is invoked with the first
set of args.
If an error, a non-zero number is returned, which represents the
error number from OS/2 or FILEREXX or the program being invoked.
Here are some possible error numbers, and their meanings (but if
the program also passes back some of these same numbers, then it
may be impossible to determine what the exact cause of the error
is):
2 File (ie, source) not found
3 Path not found
5 Access denied
26 Not DOS disk
32 Sharing violation
36 Sharing buffer exceeded
87 Invalid parameter
108 Drive locked
112 Destination disk is full
206 Filename exceeded character limit
267 Directory error
282 EAs not supported on destination
283 Need EAs found
Examples /* Invoke the program 'test.exe', specifying 'myfile' as the
source arg */
err = FileIterateExe('test.exe', 'myfile')
IF err <> 0 THEN SAY 'ERROR:' err
/* Invoke the program 'test.exe' upon all files in the C:\OS2
directory */
err = FileIterateExe('test.exe', 'C:\OS2\')
IF err <> 0 THEN SAY 'ERROR:' err
/* Invoke the program 'test.exe' upon all files in the C:\OS2
directory that end in .exe extension */
err = FileIterateExe('test.exe', 'C:\OS2\*.exe')
IF err <> 0 THEN SAY 'ERROR:' err
/* Invoke the program 'test.exe' upon all files in the C:\
directory that end in .bat extension, and also supply a
destination arg that consists of the filename with a .bak
extension instead of the .bat */
err = FileIterateExe('test.exe', 'C:\*.bat', '*.bak')
IF err <> 0 THEN SAY 'ERROR:' err
/* Do a DIR on all of the files that end with the extension .c
in the current directory. Supply the option '/W' at the end of
the line */
err = FileIterateExe(, '*.c', ,'DIR','/W')
IF err <> 0 THEN SAY 'ERROR:' err
/* Do a DIR on all of the files that end with the extension .c
in the current directory. Supply the option '/W' at the start of
the line (so we include it as part of the before arg) */
err = FileIterateExe(, '*.c', ,'DIR /W')
IF err <> 0 THEN SAY 'ERROR:' err
Also look at the examples for FileMoveFile(). The way that you
specify the source and destination are applicable to
FileIterateExe().
Note: An OS/2 command line app is included, called TEST.EXE,
which simply prints out the args that it receives upon
each invocation. You can use this to test out your call
to FileIterateExe, to ensure that the arguments are being
passed properly to a program.
#define INCL_DOSPROCESS
#include <os2.h>
#include <stdio.h>
#include <conio.h>
main(int argc, char *argv[], char *envp[])
{
ULONG i;
printf("================== %s has been invoked!
===================\n\r", argv[0]);
for (i=1; i<argc; i++)
{
printf("Arg #%d = %s\n\r", i, argv[i]);
}
printf("====================== All Done!
=======================\n\r");
DosExit(EXIT_PROCESS,0);
}
ΓòÉΓòÉΓòÉ 4.15. FileBit ΓòÉΓòÉΓòÉ
Syntax value = FileBit(Value, AdditionalArg, Operation)
Purpose Performs operations upon values expressed in binary. A value
expressed in binary has digits that are '1's or '0's. For
example, the hexadecimal byte (ie, 8 bits) of 71 is expressed in
binary as '01110001'.
Note: Be careful not to use REXX's ARG command to parse binary
expressions out of a string. ARG automatically chops off
any leading zeros on strings of digits. For example, if
you run the following:
/* */
arg val
SAY val
and supply 00110101 as the argument when invoking the script,
you'll notice that val is '110101'.
Args Value is the binary value to operation upon. Binary values are
limited to 32 bits (ie, digits).
AdditionalArg is interpreted differently depending upon the
Operation. For ROR, ROL, SHR, and SHL, this is the number of
bits to shift/rotate. For AND, OR, or XOR, AdditionalArg is the
other binary value to AND/OR/XOR with. For TEST, SET, CLR, or
FLIP, AdditionalArg is the bit number to operate upon, where 0
is the first (leftmost bit). For XTRT, AdditionalArg will be 2
numbers. The first number indicates which bit position to start
extracting at. The second number is how many bits to be
extracted. If AdditionalArg is omitted, it defaults to 0 (ie,
all 32 bits), except for XTRT, it defaults to 0 1 (ie, extract
the first bit).
Operation is one of the following:
TEST Test a specific bit (ie, return '0' if it's clear, or
'1' if it's set)
CLR Clear a specific bit (ie, change it to a '0')
SET Set a specific bit (ie, change it to a '1')
FLIP Toggle a specific bit (ie, if it was '0', change it to a
'1', and vice versa)
AND Mathematically AND the Value with the Additional Arg
OOR Mathematically OR the Value with the Additional Arg
XOR Mathematically Exclusive OR the Value with the Additional
Arg
XTRT Extract several bits.
SHR Shift all bits to the right. (Toss away bits that get
"shifted out" on the right, and replace them with 0 bits on the
left)
SHL Shift all bits to the left. (Toss away bits that get
"shifted out" on the left, and replace them with 0 bits on the
right)
ROR Rotate all bits to the right.
ROL Rotate all bits to the left.
If Operation is omitted, it defaults to TEST.
Note: The value that you pass to FileBit is not padded out to
8, 16, or 32 bits. The returned value will be the same
number of bits as the value you pass (with the exception
of TEST and XTRT). For example, if you pass '011' and do
a ROR for 1 bit, the return is '101'.
Returns The new value is returned for operations AND, OR, XOR, ROR, ROL,
SHR, SHL, SET, CLR, or FLIP. For TEST, a '0' is returned if the
bit is clear, or a '1' is returned if the bit is set. For XTRT,
only the number of bits that were requested to be extracted are
returned.
Examples /* AND '01010101' with '11110000'. The result is '01010000' */
value = FileBit('01010101', '11110000', 'AND')
SAY value
/* Set bit 0 (ie, leftmost bit) of '1111000001110000'. The
result is '1111000001110001' */
value = FileBit('1111000001110000', 0, 'SET')
SAY value
/* Extract 4 bits starting at bit 2. The result is '1100' */
value = FileBit('11110000', 2 4, 'XTRT')
SAY value
/* Test bit 7. The result is '1' */
value = FileBit('11110000', 7)
SAY value
ΓòÉΓòÉΓòÉ 4.16. FileDoSleep ΓòÉΓòÉΓòÉ
Syntax err = FileDoSleep(Milliseconds)
Purpose Allows a script to perform a delay in a manner which allows
other OS/2 programs to multi-task while your script is
"sleeping".
Note: FileDoSleep cannot be called from a script launched by a
PM application (unless that app launches the script from
a secondary thread). If FileDoSleep causes the script to
lockup when launched by PMREXX, VXREXX, VREXX, and other
visual REXX packages, that would be the problem.
(Definitely don't call FileDoSleep in a script that uses
my own visual REXX package, Rexx Dialog, also freely
available). You'll need to find some other means to do a
delay in your script.
Args Milliseconds is the amount of time to sleep, in milliseconds
(ie, 1000 milliseconds = 1 second). If you omit this arg, it
defaults to 1 second delay.
Returns If successful, a 0 is returned.
If an error, a non-zero number is returned, indicating that the
function has already timed out upon return.
Examples /* Sleep for 5000 milliseconds (ie, 5 seconds) */
err = FileDoSleep(5000)