Jump to content

REXX Tips & Tricks:Hints for Object REXX: Difference between revisions

From EDM2
Ak120 (talk | contribs)
Ak120 (talk | contribs)
 
(16 intermediate revisions by the same user not shown)
Line 1: Line 1:
This section contains some hints for using Object-Oriented REXX under OS/2. It also contains some information about Object REXX for other operating systems.
This section contains some hints for using Object-Oriented REXX under OS/2. It also contains some information about Object REXX for other operating systems.


Object REXX is currently available for OS/2, Windows NT, Windows 95, and Linux, and AIX.
[[Object REXX]] is currently available for OS/2, Windows NT, Windows 95, and Linux, and AIX.


see also
see also
- Creating "compiled" programs for Classic REXX and Object REXX
* Creating "compiled" programs for Classic REXX and Object REXX
- Writing filter programs in REXX
* Writing filter programs in REXX
- Using PMREXX
* Using PMREXX
- New REXXUTIL functions in Object REXX  
* New REXXUTIL functions in Object REXX  


==Object REXX for OS/2==
==Object REXX for OS/2==
Line 13: Line 13:
;Version:OBJREXX 6.00 18 May 1999
;Version:OBJREXX 6.00 18 May 1999
::(special version for WARP 3; May99 Update)
::(special version for WARP 3; May99 Update)
::(see Internet - Web Pages)
:OBJREXX 6.00 25 Mar 1998
:OBJREXX 6.00 25 Mar 1998
::(special version for WARP 3; Mar98 Update)
::(special version for WARP 3; Mar98 Update)
::(see Internet - Web Pages)
:OBJREXX 6.00 11 Nov 1997
:OBJREXX 6.00 11 Nov 1997
::(special version for WARP 3; Nov97 Update, also part of WARP 4 Fixpack #6)
::(special version for WARP 3; Nov97 Update, also part of WARP 4 Fixpack #6)
::(see Internet - Web Pages)
:OBJREXX 6.00 21 Jul 1997
:OBJREXX 6.00 21 Jul 1997
::(special version for WARP 3)
::(special version for WARP 3)
::(see Internet - Web Pages)
::(DevCon Rel 2 Vol 1)
::(DevCon Rel 2 Vol 1)
:OBJREXX 6.00 12 Jul 1996
:OBJREXX 6.00 12 Jul 1996
Line 32: Line 28:
;Source: WARP 4 / DevCon / (see Internet - Web Pages)
;Source: WARP 4 / DevCon / (see Internet - Web Pages)


If possible, you should use the special version for WARP 3 from the IBM WebSite (see Internet - Web Pages). Use of this version is not restricted to machines running WARP 3. It is a complete version of Object REXX and, at this time, the most up-to-date version available. This version is being promoted to users of WARP 3, since the GA version of WARP 3 did not contain a copy of Object REXX, as did WARP 4. It runs fine on WARP 4 machines.
If possible, you should use the special version for WARP 3 from the IBM WebSite. Use of this version is not restricted to machines running WARP 3. It is a complete version of Object REXX and, at this time, the most up-to-date version available. This version is being promoted to users of WARP 3, since the GA version of WARP 3 did not contain a copy of Object REXX, as did WARP 4. It runs fine on WARP 4 machines.


;Note:The CD-ROM from the book Object REXX for OS/2 WARP contains a copy of Object REXX for OS/2.
;Note:The CD-ROM from the book Object REXX for OS/2 WARP contains a copy of Object REXX for OS/2.
Line 46: Line 42:
;Bugs corrected in 99/05 release:
;Bugs corrected in 99/05 release:
*Calling function Trace() with an invalid option no longer causes an access violation.
*Calling function Trace() with an invalid option no longer causes an access violation.
*Function FORMAT() no longer creates extranuous trailing blanks for certain numbers.
*Function FORMAT() no longer creates extraneous trailing blanks for certain numbers.
*Sliding window algorithm for two digit years adjusted for some cases in Date() function.
*Sliding window algorithm for two digit years adjusted for some cases in Date() function.
*Several syntax errors reported will now show the correct source line location in the user program.
*Several syntax errors reported will now show the correct source line location in the user program.
Line 96: Line 92:
*String comparison with padded characters fails if excess character is greater than ASCII 127
*String comparison with padded characters fails if excess character is greater than ASCII 127
*SysFileTree fails to find Win95 LFN directories
*SysFileTree fails to find Win95 LFN directories
* Long message evaluation expressions not protected from garbage collection  
*Long message evaluation expressions not protected from garbage collection


;Features added in 98/10 release:
;Features added in 98/10 release:
* New input and output separators for DATE() function according to revised ANSI standard
* New input and output separators for DATE() function according to revised ANSI standard
* Use double dash -- as line comment according to request by ANSI comittee
* Use double dash - as line comment according to request by ANSI committee
* Use single dash - as line continuation character according to request by ANSI comittee
* Use single dash - as line continuation character according to request by ANSI committee
* Default stream open behaviour is now non-shared (as with classic REXX).  
* Default stream open behaviour is now non-shared (as with classic REXX).


The three new options for the stream command available to open files in shared mode are:
The three new options for the stream command available to open files in shared mode are:
Line 108: Line 104:
   allow reading and writing from other processes SHAREREAD
   allow reading and writing from other processes SHAREREAD
   allow reading from other processes SHAREWRITE
   allow reading from other processes SHAREWRITE
   allow writing from other processes  
   allow writing from other processes
   
   
  e.g.:
  e.g.:
   CALL STREAM "MYFILE.DAT","C","OPEN READ SHARED"
   CALL STREAM "MYFILE.DAT","C","OPEN READ SHARED"
   CALL STREAM "LOGFILE.TXT","OPEN BOTH SHAREREAD"
   CALL STREAM "LOGFILE.TXT","OPEN BOTH SHAREREAD"
       
 
===OBJREXX 6.00 25 Mar 1998===
===OBJREXX 6.00 25 Mar 1998===
The following is the list of fixed bugs in the version OBJREXX 6.00 25 Mar 1998:
The following is the list of fixed bugs in the version OBJREXX 6.00 25 Mar 1998:
Line 129: Line 125:
* LINES() method and built-in function didn't recognize a single character after CR/LF
* LINES() method and built-in function didn't recognize a single character after CR/LF
* Line count wrong for files ending in CR-LF-EOF
* Line count wrong for files ending in CR-LF-EOF
* WPS support not persistent between reboots  
* WPS support not persistent between reboots


===OBJREXX 6.00 11 Nov 1997===
===OBJREXX 6.00 11 Nov 1997===
Line 140: Line 136:
* External programs cannot be started in the foreground
* External programs cannot be started in the foreground
* FILESPEC returns empty string for certain filename specifications
* FILESPEC returns empty string for certain filename specifications
* Problem with line contination character in mixed CRLF/LF files
* Problem with line continuation character in mixed CRLF/LF files
* Trap after garbagge collection
* Trap after garbage collection
* Problem parsing mixed SBCS/DBCS strings
* Problem parsing mixed SBCS/DBCS strings
* Trap when trying to access memory from different processes
* Trap when trying to access memory from different processes
* Corrected a problem with duplicate freed memory in SysIni
* Corrected a problem with duplicate freed memory in SysIni
* Wrong error location for duplicate method  
* Wrong error location for duplicate method


;Added features:
;Added features:
* New functions in REXXUTIL.DLL (see New REXXUTIL functions in Object REXX)
* New functions in REXXUTIL.DLL (see New REXXUTIL functions in Object REXX)
* Enable SysIni function to work in a non-PM environment (see New REXXUTIL functions in Object REXX)  
* Enable SysIni function to work in a non-PM environment (see New REXXUTIL functions in Object REXX)


===OBJREXX 6.00 26 Feb 1997 and OBJREXX 6.00 21 Jul 1997===
===OBJREXX 6.00 26 Feb 1997 and OBJREXX 6.00 21 Jul 1997===
Line 171: Line 167:
* Delete key has no effect in PMREXX entry field
* Delete key has no effect in PMREXX entry field
* Trap when seeking not existing file
* Trap when seeking not existing file
* Hashvalue not defined for class objects
* Hash value not defined for class objects
* Error in PARSE CASELESS instruction
* Error in PARSE CASELESS instruction
* Incorrect output with .error~say
* Incorrect output with .error~say
Line 181: Line 177:
* LINEOUT does not write to correct file
* LINEOUT does not write to correct file


==Object REXX for Windows 95 / Windows NT==
==Object REXX for Windows 95/Windows NT==
Name: Object-Oriented REXX for Windows 95 / Windows NT
;Name: Object-Oriented REXX for Windows 95/Windows NT
Version: see Website for current version
;Version: see Website for current version
Author: IBM
;Author: IBM
Distrib. commercial
;Distrib: commercial
(see Internet - Web Pages)
;Type: REXX Interpreter
Type REXX Interpreter
;Price: -
Price -
;Source: IBM
Source IBM


In February 1997 IBM removed the Evaluation Copy of Object REXX for Windows 95/Windows NT from their WEB site and started to sell the Licensed version.
In February 1997 IBM removed the Evaluation Copy of Object REXX for Windows 95/Windows NT from their web site and started to sell the Licensed version.
See the Home Page for Object REXX for Windows NT and Windows 95 for additional information (see Internet - Web Pages)
See the Home Page for Object REXX for Windows NT and Windows 95 for additional information.


==Object REXX for Linux==
==Object REXX for Linux==
Name Object-Oriented REXX for Linux
;Name: Object-Oriented REXX for Linux
Version see Website for current version
;Version: see Website for current version
Author IBM
;Author: IBM
Distrib. free
;Distrib.: free
Type REXX Interpreter
;Type: REXX Interpreter
Price -
;Price: -
Source (see Internet - Web Pages)
;Source: (see Internet - Web Pages)
Note Contains the Object REXX
;Note: Contains the Object REXX documentation in PostScript format
documentation in Postscript
format


See the Web Site for more information about Object-Oriented REXX for Linux.  
See the Web Site for more information about Object-Oriented REXX for Linux.


==Object REXX for AIX==
==Object REXX for AIX==
Name Object-Oriented REXX for AIX
;Name: Object-Oriented REXX for AIX
Version see Website for current version
;Version: see Website for current version
Author IBM
;Author: IBM
Distrib. commercial
;Distrib.: commercial
Type REXX Interpreter
;Type: REXX Interpreter
Price -
;Price: -
Source (see Internet - Web Pages)
;Source: (see Internet - Web Pages)


See the Web Site for more information about Object-Oriented REXX for AIX.  
See the Web Site for more information about Object-Oriented REXX for AIX.


==How to switch from Classic REXX to Object Rexx and vice versa==
==How to switch from Classic REXX to Object Rexx and vice versa==
Line 244: Line 237:
The first thing you should do, if you're got an error in a Classic REXX program running under Object REXX, is:
The first thing you should do, if you're got an error in a Classic REXX program running under Object REXX, is:


Look in the Object REXX online documentation; especially read the section �Migration (the good old RTFM)!
Look in the Object REXX online documentation; especially read the section Migration (the good old RTFM)!


If you do not not find anything related to the error there, you can take a look at the following sections with differences between Classic REXX and Object-Oriented REXX!
If you do not not find anything related to the error there, you can take a look at the following sections with differences between Classic REXX and Object-Oriented REXX!
Line 256: Line 249:


According to the online help, CHARS() used on STDIN should return 1 if there are remaining characters in the stream or 0 if there are no more characters in the stream (That's also the way it used to work in Classic REXX).
According to the online help, CHARS() used on STDIN should return 1 if there are remaining characters in the stream or 0 if there are no more characters in the stream (That's also the way it used to work in Classic REXX).
In reality, CHARS() always returns 0 if used for STDIN.
In reality, CHARS() always returns 0 if used for STDIN.
[Tested with OBJREXX 6.00 12 Jul 1996]
[Tested with OBJREXX 6.00 12 Jul 1996]
[Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]
[Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]


(see also The function LINES() in Object REXX and The function CHARS())
(see also [[#The function LINES() in Object REXX]] and The function CHARS())


====The function DIRECTORY() in Object REXX====
====The function DIRECTORY() in Object REXX====
Line 266: Line 260:


The directory() function only maintains 1 drive at 1 time. e.g.:
The directory() function only maintains 1 drive at 1 time. e.g.:
  say directory("c:\test1")      // c:\test1
say directory("c:\test1")      // c:\test1
  say directory("d:\test2")      // d:\test2
say directory("d:\test2")      // d:\test2
  say directory("C:")            // c:\  :-(
say directory("C:")            // c:\  :-(
  say directory("D:")            // D:\  :-(
say directory("D:")            // D:\  :-(
 
This problem is NOT in the OS/2 version of Object REXX."
This problem is NOT in the OS/2 version of Object REXX."


Source: [[Mario Semo]]
Source: Mario Semo


====The function LINEOUT() in Object REXX====
====The function LINEOUT() in Object REXX====
The function �LINEOUT seems to have a bug in Object REXX.
The function LINEOUT seems to have a bug in Object REXX.


For example the REXX program below should write all three messages to the file TEST001.LOG in the current directory at program start. But in Object REXX, it writes only the first message to this file; the other two messages go into the files C:\OS2\TEST001.LOG and C:\MPTN\TEST001.LOG.
For example the REXX program below should write all three messages to the file TEST001.LOG in the current directory at program start. But in Object REXX, it writes only the first message to this file; the other two messages go into the files C:\OS2\TEST001.LOG and C:\MPTN\TEST001.LOG.
Line 408: Line 401:


====The function LINES() in Object REXX====
====The function LINES() in Object REXX====
The function LINES does not work as expected in Object-Oriented REXX:


The function �LINES does not work as expected in Object-Oriented REXX:
According to the online help, LINES() used on STDIN should return 1 if there are remaining characters in the stream or 0 if there are no more characters in the stream (That's also the way it used to work in Classic REXX).


According to the online help, LINES() used on STDIN should return 1 if there are remaining characters in the stream or 0 if there are no more characters in the stream (That's also the way it used to work in Classic REXX).
In reality, LINES() always returns 0 if used for STDIN.
In reality, LINES() always returns 0 if used for STDIN.
[Tested with OBJREXX 6.00 12 Jul 1996]
[Tested with OBJREXX 6.00 12 Jul 1996]
[Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]
[Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]


(see also The function CHARS() in Object REXX; see Writing filter programs in REXX for a workaround)  
(see also [[#The function CHARS() in Object REXX]]; see Writing filter programs in REXX for a workaround)


====The function STREAM() in Object REXX====
====The function STREAM() in Object REXX====
In Classic REXX, the statement
In Classic REXX, the statement
   myFileName = stream( "A:\test", "c"', "QUERY EXISTS" )
   myFileName = stream( "A:\test", "c"', "QUERY EXISTS" )
only returns an empty string if the drive A: is not ready. In Object-Oriented REXX this statement pops up this nice little OS/2 error box saying that the drive is not ready.
only returns an empty string if the drive A: is not ready. In Object-Oriented REXX this statement pops up this nice little OS/2 error box saying that the drive is not ready.
[Tested with OBJREXX 6.00 12 Jul 1996]
[Tested with OBJREXX 6.00 12 Jul 1996]
Line 429: Line 421:


====The function VALUE() in Object REXX====
====The function VALUE() in Object REXX====
The function �VALUE fails with the error REX0040E (Incorrect call to routine) if you're trying to change the contents of an environment variable and the length of the value of another environment variable is greater than 725.
The function VALUE fails with the error REX0040E (Incorrect call to routine) if you're trying to change the contents of an environment variable and the length of the value of another environment variable is greater than 725.


Source: Mario Semo (see EMail Addresses)
Source: Mario Semo (see EMail Addresses)
Line 470: Line 462:


====Starting new VIO/Fullscreen sessions====
====Starting new VIO/Fullscreen sessions====
The parameter handling of the Object REXX interpreter is different than the parameter handling of the Classic REXX interpreter if started via the �START command:
The parameter handling of the Object REXX interpreter is different than the parameter handling of the Classic REXX interpreter if started via the START command:


In Object REXX programs started via �START without a parameter the function arg( 1, 'e' ) always return true (there's always a parameter with the value " " [0x20]).
In Object REXX programs started via START without a parameter the function arg( 1, 'e' ) always return true (there's always a parameter with the value " " [0x20]).


Try the code below using
Try the code below using
  start test.cmd
  start test.cmd
in Classic REXX and in Object REXX and compare the results to see the difference.
in Classic REXX and in Object REXX and compare the results to see the difference.
<PRE>
<PRE>
Line 665: Line 656:
   say .BS.MYVAR
   say .BS.MYVAR
</PRE>
</PRE>
 
Note: "To avoid conflicts with future REXX-defined entries, it is recommended that entries you place in the program local environment or in the global environment include a least one period in the entry name."
Note: "To avoid conflicts with future REXX-defined entries, it is recommented that entries you place in the program local environment or in the global environment include a least one period in the entry name."


Use the environment .environment for variables global to all REXX programs. Example:
Use the environment .environment for variables global to all REXX programs. Example:
Line 685: Line 675:
       call value 'BS.MYVAR', 'Value set using the VALUE function', ''
       call value 'BS.MYVAR', 'Value set using the VALUE function', ''
</PRE>
</PRE>
Note that the environment .environment contains a lot of default variables that you should NOT change. To get a list of all existing variables you can use the following code:
Note that the environment .environment contains a lot of default variables that you should NOT change. To get a list of all existing variables you can use the following code:
<PRE>   
<PRE>   
Line 691: Line 680:
       do i over .environment
       do i over .environment
         say 'Variable "' || i || '" is "' || .environment[i] || '"'
         say 'Variable "' || i || '" is "' || .environment[i] || '"'
       end /* do i over .envrionment */
       end /* do i over .environment */


     To check if a variable is already defined, you can use the following code:
     To check if a variable is already defined, you can use the following code:
Line 706: Line 695:
       end /* else */
       end /* else */
</PRE>
</PRE>
 
Note: "To avoid conflicts with future REXX-defined entries, it is recommended that entries you place in the program local environment or in the global environment include a least one period in the entry name."
Note: "To avoid conflicts with future REXX-defined entries, it is recommented that entries you place in the program local environment or in the global environment include a least one period in the entry name."


Use the directives ::REQUIRES and ::ROUTINE to implement external routines.
Use the directives ::REQUIRES and ::ROUTINE to implement external routines.
Line 765: Line 753:
     /* ------------------------------------------------------------------ */
     /* ------------------------------------------------------------------ */
</PRE>
</PRE>
And there are a lot of very useful new functions in the REXXUTIL.DLL. See New REXXUTIL functions in Object REXX for an overview of the new functions. This section also contains information on how to use the new REXXUTIL.DLL with Classic REXX.
And there are a lot of very useful new functions in the REXXUTIL.DLL. See New REXXUTIL functions in Object REXX for an overview of the new functions. This section also contains information on how to use the new REXXUTIL.DLL with Classic REXX.


Again, read the section MIGRATION in the Online-Help of Object-Oriented REXX -- else you might miss some of the new features.
Again, read the section MIGRATION in the Online-Help of Object-Oriented REXX - else you might miss some of the new features.


==Hints for using Object REXX==
==Hints for using Object REXX==
Line 777: Line 764:
In Object REXX you can have multiple variables pointing to the same stem.; e.g. after issuing
In Object REXX you can have multiple variables pointing to the same stem.; e.g. after issuing
   b. = a.
   b. = a.
 
b. points to the same variable as a.. Note that this is not a copy operation - it's more like a shadow on the WPS. For example if you change the value b.4 the value al.4 is also changed:
b. points to the same variable as a.. Note that this is not a copy operation -- it's more like a shadow on the WPS. For example if you change the value b.4 the value al.4 is also changed:
<PRE>
<PRE>
                     /* first fill the stem a.                        */
                     /* first fill the stem a.                        */
Line 800: Line 786:
* use Object REXX as your default REXX interpreter without the Workplace Shell support (i.e., do NOT use WPSINST)!!!
* use Object REXX as your default REXX interpreter without the Workplace Shell support (i.e., do NOT use WPSINST)!!!
* create a WPS Object for the REXX program REXXTRY.CMD with:
* create a WPS Object for the REXX program REXXTRY.CMD with:
Title                   |Start Object REXX
:{|class="wikitable"
---------------------------------------------------
|Title||Start Object REXX
Path and filename       |*
|-
---------------------------------------------------
|Path and filename||*
Parameters               |/C REXXTRY.CMD
|-
---------------------------------------------------
|Parameters||/C REXXTRY.CMD
Working directory       |\
|-
|Working directory||\
|}
* create a new directory
* create a new directory
* extract the REXX program below from this INF file and save it in the new directory with the name STARTCR.CMD
* extract the REXX program below from this INF file and save it in the new directory with the name STARTCR.CMD
Line 812: Line 800:
* copy the REXX.DLL from Classic REXX into the new directory with STARTCR.CMD (This is the DLL named CREXX.DLL in \OS2\DLL if Object REXX is currently the default REXX interpreter)
* copy the REXX.DLL from Classic REXX into the new directory with STARTCR.CMD (This is the DLL named CREXX.DLL in \OS2\DLL if Object REXX is currently the default REXX interpreter)
* create a WPS Object for the REXX program STARTCR.CMD with the following setup
* create a WPS Object for the REXX program STARTCR.CMD with the following setup
Title                   |Start Classic REXX
:{|class="wikitable"
---------------------------------------------------
|Title||Start Classic REXX
Path and filename       |*
|-
---------------------------------------------------
|Path and filename||*
Parameters               |/K .\STARTCR.CMD
|-
---------------------------------------------------
|Parameters||/K .\STARTCR.CMD
Working directory       |the directory with
|-
                          |STARTCR.CMD
|Working directory||the directory with STARTCR.CMD
 
|}
Now you can select the REXX interpreter to use:
Now you can select the REXX interpreter to use:


Start the WPS object "Start Classic REXX" if you need Classic REXX or start the WPS object "Start Object REXX" if you need Object REXX. All other programs started after one of these objects will use the REXX interpreter that is loaded.
Start the WPS object "Start Classic REXX" if you need Classic REXX or start the WPS object "Start Object REXX" if you need Object REXX. All other programs started after one of these objects will use the REXX interpreter that is loaded.


Note that it is only possible to use one REXX interpreter at a time. To switch the REXX interpreter either from Classic REXX to Object REXX or vice versa you must first close all sessions using REXX, wait a bit and start the WPS object using the other REXX interpreter. Note also, that you must unload all DLLs using REXX (for example REXXUTIL.DLL) before switching the interpreter.
Note that it is only possible to use one REXX interpreter at a time. To switch the REXX interpreter either from Classic REXX to Object REXX or vice versa, you must first close all sessions using REXX, wait a bit and start the WPS object using the other REXX interpreter. Note also, that you must unload all DLLs using REXX (for example REXXUTIL.DLL) before switching the interpreter.


And last:
And last:
Line 879: Line 867:
   end /* else */
   end /* else */
  exit 0
  exit 0
(see also How to switch from Classic REXX to Object REXX and vice versa)


(see also How to switch from Classic REXX to Object Rexx and vice versa)
==Using Object REXX and the WPS==
 
==Using Object REXX and the WPS==  
It seems that the WPS part of Object REXX never finishes its initialisation part and therefore has to be forced to do so to use the WPS classes in Object REXX programs.
It seems that the WPS part of Object REXX never finishes its initialisation part and therefore has to be forced to do so to use the WPS classes in Object REXX programs.
You can force the finishing of the initialisation by opening the Template folder for example - but that's no general solution of course.
You can force the finishing of the initialisation by opening the Template folder for example - but that's no general solution of course.
Line 888: Line 875:
To test if this bug occurs on your system, simply issue the command
To test if this bug occurs on your system, simply issue the command
   rexxtry say .wps
   rexxtry say .wps
If the output is '''''.WPS''''' then the error occurs on your system.
If the output is '''''.WPS''''' then the error occurs on your system.


As a workaround to the WPS Server not getting initialized you can put a program object with the following settings in your startup folder:
As a workaround to the WPS Server not getting initialized, you can put a program object with the following settings in your startup folder:
  Program = c:\os2\wpsinst.cmd
  Program = c:\os2\wpsinst.cmd
  Parameter = +
  Parameter = +
 
This may help ensure that the WPS part of Object REXX finishes its initialisation at startup (note that not all who have tried this have reported success).
This may help ensure that the WPS part of Object REXX finishes its initialization at startup (note that not all who have tried this have reported success).


[Fixed in OBJREXX 6.00 25 Mar 1998 and newer versions]
[Fixed in OBJREXX 6.00 25 Mar 1998 and newer versions]
Line 903: Line 888:
To use Object REXX with Object Desktop you only need to deinstall the "Enhanced Folder" Component of Object Desktop - that's the only part of Object Desktop that is affected by Object REXX.
To use Object REXX with Object Desktop you only need to deinstall the "Enhanced Folder" Component of Object Desktop - that's the only part of Object Desktop that is affected by Object REXX.


If you want to keep Object Desktop's Enhanced Folder on your desktop, all you need to do is to NOT install the WPS classes of Object REXX (these are the classes initialized by the wpsinst.cmd program). Object REXX will still be loaded and you'll still have access to all Object REXX commands, except the ones involving the new classes.  
If you want to keep Object Desktop's Enhanced Folder on your desktop, all you need to do is to NOT install the WPS classes of Object REXX (these are the classes initialized by the wpsinst.cmd program). Object REXX will still be loaded, and you'll still have access to all Object REXX commands, except the ones involving the new classes.


==Writing OS-independent programs in Object REXX==
==Writing OS-independent programs in Object REXX==
If you want to write operating system independent programs using Object REXX, you should keep the following differences between Object REXX for OS/2 and Object REXX for Windows 95 / Windows NT in mind:
If you want to write operating system independent programs using Object REXX, you should keep the following differences between Object REXX for OS/2 and Object REXX for Windows 95 / Windows NT in mind:
* in the Windows version, the environment is process-local
*in the Windows version, the environment is process-local
* in the Windows version, host commands are executed in a new process
*in the Windows version, host commands are executed in a new process
* on Windows 95, host commands always return 0
*on Windows 95, host commands always return 0
* Object REXX on Windows does not support SOM, and the DBCS support is not documented
*Object REXX on Windows does not support SOM, and the DBCS support is not documented
* in both versions (Win95 and OS/2) you should use VALUE( envVarName, envVarValue, 'ENVIRONMENT' ) to set or read environment variables
*in both versions (Win95 and OS/2) you should use VALUE( envVarName, envVarValue, 'ENVIRONMENT' ) to set or read environment variables
* in both versions (Win95 and OS/2) you should use VALUE( envVarName, .NIL, 'ENVIRONMENT' ) to delete an environment variable  
*in both versions (Win95 and OS/2) you should use VALUE( envVarName, .NIL, 'ENVIRONMENT' ) to delete an environment variable


More information about Object REXX for the Windows platform can be found at the Object REXX home page (see Internet - Web Pages).
More information about Object REXX for the Windows platform can be found at the Object REXX home page (see Internet - Web Pages).
Line 918: Line 903:
==Adding Object REXX Support to a maintenance partition==
==Adding Object REXX Support to a maintenance partition==
To add Object REXX to a maintenance partition (created with BOOTOS2 for example) do the following:
To add Object REXX to a maintenance partition (created with BOOTOS2 for example) do the following:
# Create the maintenance parition without REXX support. (In the statements below I assume that F: is the drive letter for the maintenance partition)
# Create the maintenance partition without REXX support. (In the statements below I assume that F: is the drive letter for the maintenance partition)
# Create a new directory on the maintenance partition (e.g. F:\OREXX)
# Create a new directory on the maintenance partition (e.g. F:\OREXX)
# Add the new directory to the PATH, LIBPATH and DPATH statement in the file F:\CONFIG.SYS
# Add the new directory to the PATH, LIBPATH and DPATH statement in the file F:\CONFIG.SYS
# Copy the following files from your existing OS/2 partition with activated Object REXX support to the new directory F:\OREXX:
# Copy the following files from your existing OS/2 partition with activated Object REXX support to the new directory F:\OREXX:
OS2\DLL\NAMEREXX.DLL
#:OS2\DLL\NAMEREXX.DLL
OS2\DLL\PMREXXIO.DLL
#:OS2\DLL\PMREXXIO.DLL
OS2\DLL\REXX.DLL
#:OS2\DLL\REXX.DLL
OS2\DLL\REXXAPI.DLL
#:OS2\DLL\REXXAPI.DLL
OS2\DLL\REXXCRT.DLL
#:OS2\DLL\REXXCRT.DLL
OS2\DLL\REXXINIT.DLL
#:OS2\DLL\REXXINIT.DLL
OS2\DLL\REXXSC.DLL
#:OS2\DLL\REXXSC.DLL
OS2\DLL\REXXSOM.DLL
#:OS2\DLL\REXXSOM.DLL
OS2\DLL\REXXUTIL.DLL
#:OS2\DLL\REXXUTIL.DLL
OS2\DLL\REXXWPS.DLL
#:OS2\DLL\REXXWPS.DLL
OS2\DLL\SOMD.DLL
#:OS2\DLL\SOMD.DLL
OS2\DLL\SOMSEC.DLL
#:OS2\DLL\SOMSEC.DLL
OS2\DLL\SOM.DLL
#:OS2\DLL\SOM.DLL
OS2\DLL\SOMEM.DLL
#:OS2\DLL\SOMEM.DLL
OS2\DLL\SOMIR.DLL
#:OS2\DLL\SOMIR.DLL
OS2\DLL\SOMS.DLL
#:OS2\DLL\SOMS.DLL
OS2\DLL\SOMTC.DLL
#:OS2\DLL\SOMTC.DLL
OS2\DLL\SOMU.DLL
#:OS2\DLL\SOMU.DLL
OS2\DLL\SOMUC.DLL
#:OS2\DLL\SOMUC.DLL
OS2\SYSTEM\REX.MSG
#:OS2\SYSTEM\REX.MSG
OS2\SYSTEM\REXH.MSG
#:OS2\SYSTEM\REXH.MSG
OS2\REXXTRY.CMD
#:OS2\REXXTRY.CMD
OS2\PMREXX.EXE
#:OS2\PMREXX.EXE
OS2\REXXC.EXE
#:OS2\REXXC.EXE
OS2\REXX.ICO
#:OS2\REXX.ICO
OS2\REXX.IMG
#:OS2\REXX.IMG
OS2\WPREXX.IMP
#:OS2\WPREXX.IMP
# Copy the file BOS2REXX.EXE from the BOOTOS2-Package to the new directory.  
# Copy the file BOS2REXX.EXE from the BOOTOS2-Package to the new directory.
# Add the line
# Add the line <tt>RUN=F:\OREXX\BOS2REXX.EXE</tt> to the file F:\CONFIG.SYS
RUN=F:\OREXX\BOS2REXX.EXE
to the file F:\CONFIG.SYS
# Reboot from the maintenance partition and test the REXX support (for example with REXXTRY)
# Reboot from the maintenance partition and test the REXX support (for example with REXXTRY)


[[Category:Scripting Articles]]
[[Category:REXX Tips & Tricks]]

Latest revision as of 19:19, 10 March 2024

This section contains some hints for using Object-Oriented REXX under OS/2. It also contains some information about Object REXX for other operating systems.

Object REXX is currently available for OS/2, Windows NT, Windows 95, and Linux, and AIX.

see also

  • Creating "compiled" programs for Classic REXX and Object REXX
  • Writing filter programs in REXX
  • Using PMREXX
  • New REXXUTIL functions in Object REXX

Object REXX for OS/2

Name
Object-Oriented REXX for OS/2
Version
OBJREXX 6.00 18 May 1999
(special version for WARP 3; May99 Update)
OBJREXX 6.00 25 Mar 1998
(special version for WARP 3; Mar98 Update)
OBJREXX 6.00 11 Nov 1997
(special version for WARP 3; Nov97 Update, also part of WARP 4 Fixpack #6)
OBJREXX 6.00 21 Jul 1997
(special version for WARP 3)
(DevCon Rel 2 Vol 1)
OBJREXX 6.00 12 Jul 1996
(WARP 4)
Author
IBM
Distrib.
Part of WARP 4 and free through the web
Type
REXX Interpreter
Price
-
Source
WARP 4 / DevCon / (see Internet - Web Pages)

If possible, you should use the special version for WARP 3 from the IBM WebSite. Use of this version is not restricted to machines running WARP 3. It is a complete version of Object REXX and, at this time, the most up-to-date version available. This version is being promoted to users of WARP 3, since the GA version of WARP 3 did not contain a copy of Object REXX, as did WARP 4. It runs fine on WARP 4 machines.

Note
The CD-ROM from the book Object REXX for OS/2 WARP contains a copy of Object REXX for OS/2.

The following are lists of fixed bugs in the updated versions of Object REXX

The following is the list of fixed bugs in the version

OBJREXX 6.00 18 May 1999

ENHANCEMENTS TO OBJECT REXX

The following enhancements have been made to this Object REXX level:

Bugs corrected in 99/05 release
  • Calling function Trace() with an invalid option no longer causes an access violation.
  • Function FORMAT() no longer creates extraneous trailing blanks for certain numbers.
  • Sliding window algorithm for two digit years adjusted for some cases in Date() function.
  • Several syntax errors reported will now show the correct source line location in the user program.
  • A single LF that falls on the internal buffer boundary is no longer ignored.
  • Piped input no longer contains additional characters.
  • Literals no longer cause and error with the VALUE() function.
  • DATE("S") with output separator specified now formatted correctly.
  • Memory leak when reading from streams has been removed.
  • Memory leak when creating many stream objects has been removed.
  • ARRAYIN method of the stream class no longer raises the NOTREADY condition.
  • When a stack overflow is encountered it will be handled correctly without causing an application error.
  • RANDOM(1,,99) no longer causes an application error.
  • STREAM("STDIN","C","CLOSE) no longer causes a trap.
Features added in 99/05 release
  • New REXXUTIL functions:
    • SysDumpVariables
    • SysGetFileDateTime
    • SysSetFileDateTime
    • SysStemCopy
    • SysStemDelete
    • SysStemInsert
    • SysStemSort
    • SysUtilVersion
    • SysVersion
  • If the first line contains a Unix style shell definition starting with #! it will be ignored (seen as a comment).

OBJREXX 6.00 Oct 1998

ENHANCEMENTS TO OBJECT REXX

The following enhancements have been made to this Object REXX level:

Bugs corrected in 98/10 release
  • Calling function Trace() with an invalid option no longer causes an access violation.
  • OPTIONS EXMODE not working correctly
  • SysFileTree did not work correctly with absolute path from root (e.g. "\OS2")
  • Subclassing class STREAM could cause a trap
  • Closing files after changing directories sometimes did not work
  • Broken error message for bad hexadecimal strings
  • Internal memory handling problem
  • Trap with many threads depending on timing at thread termination
  • DO..OVER binary files caused system resources to be exhausted
  • UNINIT method not called when defined in a parent class
  • Last line was ignored by SysFileSearch when not terminated with CR/LF
  • Drop of an object didn't invoke the UNINIT method
  • Stream SEEK command no longer requires READ/WRITE attribute, if none is specified BOTH is assumed (to be compatible with classic REXX)
  • TRANSLATE("abc","","") gives incorrect result
  • Trap or unpredictable results with long parse statements
  • Accessing an unqualified filename (no path information) sometimes failed after changing the current directory
  • String comparison with padded characters fails if excess character is greater than ASCII 127
  • SysFileTree fails to find Win95 LFN directories
  • Long message evaluation expressions not protected from garbage collection
Features added in 98/10 release
  • New input and output separators for DATE() function according to revised ANSI standard
  • Use double dash - as line comment according to request by ANSI committee
  • Use single dash - as line continuation character according to request by ANSI committee
  • Default stream open behaviour is now non-shared (as with classic REXX).

The three new options for the stream command available to open files in shared mode are:

SHARED
  allow reading and writing from other processes SHAREREAD
  allow reading from other processes SHAREWRITE
  allow writing from other processes

e.g.:
  CALL STREAM "MYFILE.DAT","C","OPEN READ SHARED"
  CALL STREAM "LOGFILE.TXT","OPEN BOTH SHAREREAD"

OBJREXX 6.00 25 Mar 1998

The following is the list of fixed bugs in the version OBJREXX 6.00 25 Mar 1998:

ENHANCEMENTS TO OBJECT REXX

The following enhancements have been made to this Object REXX level:

Corrected several bugs
  • SysFileTree error when using the 'O' option
  • Speed up processing of LINES() built-in function
  • Stream Query Size returns wrong value for not existing files
  • Memory problems with objects larger than 16 MB
  • CHARS() built-in function returned -1 for certain files
  • Memory leak when working with many files
  • LINES() method and built-in function didn't recognize a single character after CR/LF
  • Line count wrong for files ending in CR-LF-EOF
  • WPS support not persistent between reboots

OBJREXX 6.00 11 Nov 1997

The following is the list of fixed bugs in the version OBJREXX 6.00 11 Nov 1997:

ENHANCEMENTS TO OBJECT REXX

The following enhancements have been made to this Object REXX level:

Corrected several bugs
  • External programs cannot be started in the foreground
  • FILESPEC returns empty string for certain filename specifications
  • Problem with line continuation character in mixed CRLF/LF files
  • Trap after garbage collection
  • Problem parsing mixed SBCS/DBCS strings
  • Trap when trying to access memory from different processes
  • Corrected a problem with duplicate freed memory in SysIni
  • Wrong error location for duplicate method
Added features
  • New functions in REXXUTIL.DLL (see New REXXUTIL functions in Object REXX)
  • Enable SysIni function to work in a non-PM environment (see New REXXUTIL functions in Object REXX)

OBJREXX 6.00 26 Feb 1997 and OBJREXX 6.00 21 Jul 1997

The following is the list of fixed bugs in the versions OBJREXX 6.00 26 Feb 1997 and OBJREXX 6.00 21 Jul 1997:

ENHANCEMENTS TO OBJECT REXX

The following enhancements have been made to this Object REXX level:

Corrected several bugs
  • Trap in deep recursive algorithms
  • Problems with CR/LF literal translation in output streams
  • Data files not written if session exited with "EXIT"
  • RexxVariablePool did not return EXITNAME symbol
  • SysFileSearch quits at EOF in the middle of the file
  • Problems with intersection operations on collections
  • Bad count in SysFileSearch with mixed LF, CR/LF line feeds
  • Trap when called from IBM Internet Connection Server
  • CHARS() and LINES() return 0 for redirected STDIN
  • Trap in recursive invocation of STRING method
  • Delete key has no effect in PMREXX entry field
  • Trap when seeking not existing file
  • Hash value not defined for class objects
  • Error in PARSE CASELESS instruction
  • Incorrect output with .error~say
  • Standard streams not recognized with colon in name
  • Propagate error/halt conditions from OREXX image
  • Hard error popup in STREAM("A:\TEST.DAT","C","QUERY EXISTS")
  • Concurrent start of program fails sometimes
  • Problem setting OS/2 environment
  • LINEOUT does not write to correct file

Object REXX for Windows 95/Windows NT

Name
Object-Oriented REXX for Windows 95/Windows NT
Version
see Website for current version
Author
IBM
Distrib
commercial
Type
REXX Interpreter
Price
-
Source
IBM

In February 1997 IBM removed the Evaluation Copy of Object REXX for Windows 95/Windows NT from their web site and started to sell the Licensed version. See the Home Page for Object REXX for Windows NT and Windows 95 for additional information.

Object REXX for Linux

Name
Object-Oriented REXX for Linux
Version
see Website for current version
Author
IBM
Distrib.
free
Type
REXX Interpreter
Price
-
Source
(see Internet - Web Pages)
Note
Contains the Object REXX documentation in PostScript format

See the Web Site for more information about Object-Oriented REXX for Linux.

Object REXX for AIX

Name
Object-Oriented REXX for AIX
Version
see Website for current version
Author
IBM
Distrib.
commercial
Type
REXX Interpreter
Price
-
Source
(see Internet - Web Pages)

See the Web Site for more information about Object-Oriented REXX for AIX.

How to switch from Classic REXX to Object Rexx and vice versa

To switch from Object REXX to Classic REXX or vice versa execute

switchrx

in an OS/2 window and reboot the machine.

If you want to use the WPS support of Object REXX (only possible if Object REXX is the active REXX interpreter!) you must activate it using

wpsinst +

in an OS/2 window.

Use wpsinst with the parameter - to deactivate the WPS support (see also Object REXX and the WPS) Note that due to a bug in wpsinst.cmd the "wpsinst ?" does not work as expected: There's no output at all if the WPS support is not registered.

To check, which REXX version is currently running execute

rexxtry parse version t; say t;

in an OS/2 command window.

If the output is similar to OBJREXX 6.00 18 May 1999 your current REXX interpreter is Object REXX else not.

(see also Using Classic REXX if Object REXX is the default REXX)

Differences between Classic REXX and Object REXX

Normally, all REXX programs written in Classic REXX should run under Object REXX without any changes. But there are some minor changes and bugs in Object REXX that might lead to an error in your Classic REXX programs.

The first thing you should do, if you're got an error in a Classic REXX program running under Object REXX, is:

Look in the Object REXX online documentation; especially read the section Migration (the good old RTFM)!

If you do not not find anything related to the error there, you can take a look at the following sections with differences between Classic REXX and Object-Oriented REXX!

Please use only this order for checking for problems, because I'm not going to repeat the facts already mentioned in the Object REXX online documentation.

OK, now that it's hopefully clear what information you can find in this section, let's begin.

The function CHARS() in Object REXX

The function CHARS does not work as expected in Object-Oriented REXX:

According to the online help, CHARS() used on STDIN should return 1 if there are remaining characters in the stream or 0 if there are no more characters in the stream (That's also the way it used to work in Classic REXX).

In reality, CHARS() always returns 0 if used for STDIN. [Tested with OBJREXX 6.00 12 Jul 1996] [Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]

(see also #The function LINES() in Object REXX and The function CHARS())

The function DIRECTORY() in Object REXX

"There is a bug in OORexx/NT which is in the GA product, but will be fixed in WARP 4 Fixpack #1. (according to the developers).

The directory() function only maintains 1 drive at 1 time. e.g.:

say directory("c:\test1")      // c:\test1
say directory("d:\test2")      // d:\test2
say directory("C:")            // c:\   :-(
say directory("D:")            // D:\   :-(

This problem is NOT in the OS/2 version of Object REXX."

Source: Mario Semo

The function LINEOUT() in Object REXX

The function LINEOUT seems to have a bug in Object REXX.

For example the REXX program below should write all three messages to the file TEST001.LOG in the current directory at program start. But in Object REXX, it writes only the first message to this file; the other two messages go into the files C:\OS2\TEST001.LOG and C:\MPTN\TEST001.LOG.

[Tested with OBJREXX 6.00 12 Jul 1996]

[Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]

/*                                                                    */
/* sample program to show a bug in the LineOut routine in Object REXX */
/*                                                                    */

                    /* set the name for the logfile                   */
  logFileName = ILog( 'TEST001.LOG' )
                    /* logFileName now contains the fully qualified   */
                    /* name of the logfile                            */

                    /* write the name of the logfile to the screen    */
  say 'MAIN: logFileName is : "' || logFileName || '"'
  say '      Current directory is : "' || directory() || '"'

                    /* write something to the logfile                 */
                    /* Note: This is written to the *correct* logfile */
  call log 'Testing 1, currrent directory is ' || directory()

                    /* write the name of the logfile to the screen    */
  say 'MAIN: logFileName is : "' || logFileName || '"'
  say '      Current directory is : "' || directory() || '"'

                    /* now change the directory                       */
  call directory 'C:\OS2'

                    /* write the name of the logfile to the screen    */
  say 'MAIN: logFileName is : "' || logFileName || '"'
  say '      Current directory is : "' || directory() || '"'

                    /* ... and write something to the logfile         */
                    /* Note: This goes to the file C:\OS2\TEST001.LOG */
                    /*       and not into the correct logfile!!!      */
  call log 'Testing 2, currrent directory is ' || directory()

                    /* now change the directory again                 */
  call directory 'C:\MPTN'

                    /* write the name of the logfile to the screen    */
  say 'MAIN: logFileName is : "' || logFileName || '"'
  say '      Current directory is : "' || directory() || '"'

                    /* ... and write something to the logfile         */
                    /* Note: This goes to the file C:\MPTN\TEST001.LOG*/
                    /*       and not into the correct logfile!!!      */
  call log 'Testing 3, currrent directory is ' || directory()

                    /* write the name of the logfile to the screen    */
  say 'MAIN: logFileName is : "' || logFileName || '"'
  say '      Current directory is : "' || directory() || '"'

exit

/* ------------------------------------------------------------------ */
/*-function: get the fully qualified name of the logfile              */
/*                                                                    */
/*-call:     ilog logfilename                                         */
/*                                                                    */
/*-where:    logfilename - name of the logfile                        */
/*                                                                    */
/*-returns:  fully qualified name of the logfile                      */
/*                                                                    */
/*                                                                    */
ILOG: PROCEDURE
  parse arg logFilename

                        /* open or create the logfile                 */
  logStatus = stream( logFileName, 'c', 'OPEN WRITE')
  if logStatus <> 'READY:' then
  do
    say 'Error: Cannot create the logfile "' || logFileName || '"!'
    exit 255
  end /* if */

                        /* close the logfile                          */
  call stream logFileName, 'c', 'CLOSE'

                        /* get the fully qualified name of the        */
                        /* logfile                                    */
  newLogFileName = translate( stream( logFileName, 'c', 'QUERY EXISTS' ) )

                    /* write the name of the logfile to the screen    */
  say 'ILOG: logFileName is : "' || newLogFileName || '"'
  say '      Current directory is : "' || directory() || '"'

RETURN newLogFileName

/* ------------------------------------------------------------------ */
/*-function: log a message and clear the rest of the line             */
/*                                                                    */
/*-call:     log message                                              */
/*                                                                    */
/*-where:    message - message to show                                */
/*                                                                    */
/*-returns:  ''                                                       */
/*                                                                    */
/*-Note:     You do not need the 'call' keyword to use this routine.  */
/*           The name of the logfile is saved in the global variable  */
/*           'logFileName'.                                           */
/*                                                                    */
Log: PROCEDURE expose logFileName
  parse arg logmsg

                    /* write the name of the logfile to the screen    */
  say ' LOG: logFileName is : "' || logFileName || '"'
  say '      Current directory is : "' || directory() || '"'

                    /* error occurs also if the file is explicitly    */
                    /* opened before writing to the file!             */
/*
  rc = stream( logFileName, 'c', 'OPEN WRITE')
*/

  call lineout logFileName, logmsg

                    /* the error does *not* occur, if the logfile is  */
                    /* *not* closed                                   */

                    /* close the logfile                              */
  rc = stream( logFileName, 'c', 'CLOSE')

RETURN ''

The function LINES() in Object REXX

The function LINES does not work as expected in Object-Oriented REXX:

According to the online help, LINES() used on STDIN should return 1 if there are remaining characters in the stream or 0 if there are no more characters in the stream (That's also the way it used to work in Classic REXX).

In reality, LINES() always returns 0 if used for STDIN. [Tested with OBJREXX 6.00 12 Jul 1996] [Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]

(see also #The function CHARS() in Object REXX; see Writing filter programs in REXX for a workaround)

The function STREAM() in Object REXX

In Classic REXX, the statement

 myFileName = stream( "A:\test", "c"', "QUERY EXISTS" )

only returns an empty string if the drive A: is not ready. In Object-Oriented REXX this statement pops up this nice little OS/2 error box saying that the drive is not ready. [Tested with OBJREXX 6.00 12 Jul 1996] [Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]

To avoid this, you need to put the AUTOFAIL (CONFIG.SYS statements used by OS/2) statement in your CONFIG.SYS file.

The function VALUE() in Object REXX

The function VALUE fails with the error REX0040E (Incorrect call to routine) if you're trying to change the contents of an environment variable and the length of the value of another environment variable is greater than 725.

Source: Mario Semo (see EMail Addresses) [Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]

The Signal handling in Object REXX

The handling of the halt signal seems to be buggy in Object-Oriented REXX; for example the signal handling does not work in the following REXX program.

[Tested with OBJREXX 6.00 12 Jul 1996]

[Fixed in OBJREXX 6.00 26 Feb 1997 and newer versions (included in WARP 4 Fixpack #6)]

/*                                                                    */
/* example for a bug in the signal handling in Object REXX            */
/*                                                                    */
/* Source: Found in a message in a public news group                  */
/*                                                                    */
/* Hint: To get around the bug shown in this example, you can use the */
/*       function LineOut() instead of the SAY statement.             */
/*                                                                    */

 call on halt

 do forever
   say "Testing (press CTRL-C or CTRL-BREAK) ..."
 end;

exit

Halt:

  say "Abort the program? "
  userInput = translate( lineIn() )
  if userInput = "Y" then
    exit

return

Starting new VIO/Fullscreen sessions

The parameter handling of the Object REXX interpreter is different than the parameter handling of the Classic REXX interpreter if started via the START command:

In Object REXX programs started via START without a parameter the function arg( 1, 'e' ) always return true (there's always a parameter with the value " " [0x20]).

Try the code below using

start test.cmd

in Classic REXX and in Object REXX and compare the results to see the difference.

/* test.cmd */
  parse arg arguments
  say
  say
  say 'The result of  "arg( 1, ''e'' )" is  "' || arg( 1, 'e' ) || '".'
  say
  say 'Arguments are "'  || arguments || '" (in hex: "' || c2x( arguments ) || '".)'
  say
  parse version versionString
  say "REXX interpreter is " versionString
  say

  "pause"

New features in Object REXX that are useful in Classic REXX programs also

This section contains a list of some new features in Object-Oriented REXX that are useful even for Classic REXX programs.

Please do not forget to check the version of the REXX interpreter you're using with your REXX programs before you attempt to use on of these features!

DO i OVER stem

This is a very useful enhancement of DO loops. Now you can simply walk over all elements of a stem without knowing the tails:

                    /* drop all stem entries                         */
  drop myStem.

  do i = 1 to 40
    j = random( 400 )
    myStem.j = 1
  end /* do i = 1 to 40 */

  do i over myStem.
                    /* "i" contains the name of the next tail         */
                    /* (to get the value use "myStem.i")              */
    say 'The ' || i || ' was at least one time set'
    say 'The ' || myStem.i || ' was at least one time set'
  end /* do i over myStem */

Returning a stem variable

In Object-Oriented REXX a routine can return a stem variable. Example:

/* */
  test. = test1()

  do i = 1 to test.0
    say test.i
  end

return

test1:
                    /* init a local stem ...                          */
  a.0 = 3
  a.1 = 11
  a.2 = 22
  a.3 = 33
                    /* ... and return it to the calling routine.      */
return a.

Calculations and other stem variables are now possible to get or set a stem variable.

Example:

/* init a stem with sample values                                     */
  do i = 1 to 500;
    test.i = i * 2
  end /* do */
  test.0 = 500

/* access the stem in the Classic way                                 */

  say test.5        /* (1)                                            */

  j = 4+55          /* (2)                                            */
  say test.j

  i = test.4        /* (3)                                            */
  say test.i

  i = test.4        /* (4)                                            */
  j = test.i
  say test.j

/* use the new way                                                    */

  say test.[5]      /* (1)                                            */

  say test.[4+55]   /* (2)                                            */

  say test.[test.4] /* (3)                                            */

                    /* (4)                                            */
  say test.[test.[test.4]]

PARSE [upper|lower|caseless]

The PARSE instruction now supports lower and caseless parsing.

Call-by-Reference-Parameters are now possible for internal and external REXX procedures (at least for stem variables):

/* */

  say
  say 'Sample code to show the usage of USE ARG in Object REXX '
  say

  j.0 = 2
  j.1 = 111
  j.2 = 222

  say 'Values of the variables before calling the sub routine:'
  say
  say '  j.0 is ' || j.0
  do k = 1 to j.0
    say '   j.' || k || ' is ' || j.k
  end /* do */

  say
  say 'Now calling TestUseArg ...'
  say
  call TestUseArg j.

  say
  say 'Values of the variables after calling the sub routine:'
  say
  say '  j.0 is ' || j.0
  do k = 1 to j.0
    say '   j.' || k || ' is ' || j.k
  end /* do */

exit

TestUseArg: PROCEDURE
  use arg local_j.

                    /* local_j points to the global stem j.           */
  local_j.0 = 3
  local_j.1 = '111 - one'
  local_j.2 = '222 - two'
  local_j.3 = '333 - three'

return

CALL

CALL now accepts variables that are evaluated before the CALL statement is executed:

/*                                                                    */

  myRoutine = 'MYTEST'
  call (myRoutine)
exit

MYTEST:
  say 'This is mytest!'
RETURN

Plese note that the contents of the variable must be in uppercase if calling an internal routine. This is not clearly stated in the online help.

DATE

DATE is not restricted to the current date any more. Now you can use the results of this function for date calculations (e.g. How many days are between day 1 and day 2?).

STREAM

STREAM now supports some more commands and options; for example FLUSH, REPLACE (rewrite a file without doing a DEL first), and NOBUFFER. It also supports line-related positioning for files with fixed and variable length records. And there are now two different file pointers for every file -- one for reading from it and one for writing to it.

TIME

TIME is not restricted to the current time any more. This allows calculations with time stamps.

Use the environment .local for variables global to the current process. Example:

/* create a variable global to the current process                    */
  .local['BS.MYVAR'] = 'This is a global variable'

/* call an external REXX routine to show that it works                */
  call rexxtry "say .local['BS.MYVAR'] "

  call rexxtry ".local['BS.MYVAR'] = 'This variable is set by REXXTRY'"

  say .local['BS.MYVAR']

/* you can also use the following code to read the variable           */
/* But be aware of the search order for environment symbols in        */
/* Object REXX!                                                       */
  say .BS.MYVAR

Note: "To avoid conflicts with future REXX-defined entries, it is recommended that entries you place in the program local environment or in the global environment include a least one period in the entry name."

Use the environment .environment for variables global to all REXX programs. Example:

    /* create a variable global to all REXX programs                      */
      .environment['BS.MYVAR'] = 'This is a global variable'

    /* start a REXX program in another process to show that it works      */
      "cmd /c rexxtry say .environment['BS.MYVAR'] "

      "cmd /c rexxtry .environment['BS.MYVAR'] = 'This variable is set by REXXTRY'"

      say .environment['BS.MYVAR']

    /* you can also use the following code to read or change the variable */
      say value( 'BS.MYVAR',,'' )

      call value 'BS.MYVAR', 'Value set using the VALUE function', ''

Note that the environment .environment contains a lot of default variables that you should NOT change. To get a list of all existing variables you can use the following code:

   
    /* show all variables in the environment .environment                 */
      do i over .environment
        say 'Variable "' || i || '" is "' || .environment[i] || '"'
      end /* do i over .environment */

    To check if a variable is already defined, you can use the following code:

     
    /* check if a variables is defined in the environment .environment    */
      globalVar = 'BS.MYVAR'
      if .environment[globalVar] = .NIL then
        say 'Environment symbol "' || globalVar || '" is not defined.'
      else
      do
        say 'Environment symbol "' || globalVar || '" is defined;'
        say 'the value is "' || .environment[globalVar] || '".'
      end /* else */

Note: "To avoid conflicts with future REXX-defined entries, it is recommended that entries you place in the program local environment or in the global environment include a least one period in the entry name."

Use the directives ::REQUIRES and ::ROUTINE to implement external routines.

Use the keyword instruction RAISE to raise a condition in the calling routine. This is very handy to avoid endless return code evaluations.

Example:

     
    /* ------------------------------------------------------------------ */
    /* save this code in the file 'TEST1.CMD'                             */

      parse source . . thisFile
      say 'This is ' || thisFile || '.'

                        /* install an error handler for user condition 4  */
      call on user 4 name ErrorRaised

      say 'Now calling TEST2.CMD. TEST2.CMD will raise an user condition ...'

                        /* now call TEST2.CMD; test2.cmd will raise an    */
                        /* user condition                                 */
      call TEST2.CMD

      say 'Now ending the test program.'
    exit

    /* ------------------------------------------------------------------ */
    /* simple handler for the user condition 4                            */
    ErrorRaised:
      say
      say '*** start of user condition handler ***'
      say
      say 'Condition "' || condition( 'C') || '" raised in line ' || ,
          sigl || '.'
      say 'The condition description is "' || condition( 'D' ) ||  '".'
      say 'Additional information is "' || condition( 'A' ) || '".'
      say
      say '*** end of user condition handler ***'
      say
    return

     
    /* ------------------------------------------------------------------ */
    /* save this code to TEST2.CMD                                        */

      parse arg thisArgs

      parse source . . thisFile
      say '  This is "' || thisFile || '".'
      say '   Called with "' || thisArgs || '".'

                        /* raise a user condition to the caller           */
      raise user 4 ,
            Description 'This is a user error' ,
            Additional 'This is additional information'
    exit
    /* ------------------------------------------------------------------ */

And there are a lot of very useful new functions in the REXXUTIL.DLL. See New REXXUTIL functions in Object REXX for an overview of the new functions. This section also contains information on how to use the new REXXUTIL.DLL with Classic REXX.

Again, read the section MIGRATION in the Online-Help of Object-Oriented REXX - else you might miss some of the new features.

Hints for using Object REXX

This section contains some hints for using the new features in Object REXX.

Using more than one variable pointing to a stem

In Object REXX you can have multiple variables pointing to the same stem.; e.g. after issuing

 b. = a.

b. points to the same variable as a.. Note that this is not a copy operation - it's more like a shadow on the WPS. For example if you change the value b.4 the value al.4 is also changed:

                    /* first fill the stem a.                         */
  do i = 1 to 10
    a.i = i*i
  end /* do */
                    /* let b. point to the same stem as a.            */
  b. = a.
                    /* change an entry using b.                       */
  b.4 = 17
                    /* examine the fourth entry of a.                 */
  say "a.4 is" a.4
                    /* -> "a.4 is 17"                                 */

BTW: Dropping a. in this example does not discard the variable because b. points to the same variable.

Using Classic REXX if Object REXX is the default REXX

Sometimes it's necessary to test your REXX programs under Classic REXX and under Object REXX. Therefore it would be useful to use both interpreters without rebooting each time you change the REXX interpreter.

This is possible under OS/2 if you use the following approach:

  • use Object REXX as your default REXX interpreter without the Workplace Shell support (i.e., do NOT use WPSINST)!!!
  • create a WPS Object for the REXX program REXXTRY.CMD with:
Title Start Object REXX
Path and filename *
Parameters /C REXXTRY.CMD
Working directory \
  • create a new directory
  • extract the REXX program below from this INF file and save it in the new directory with the name STARTCR.CMD
  • ensure that your LIBPATH contains the entry '.;' before the entry \OS2\DLL (You need to reboot once if you must change your LIBPATH)
  • copy the REXX.DLL from Classic REXX into the new directory with STARTCR.CMD (This is the DLL named CREXX.DLL in \OS2\DLL if Object REXX is currently the default REXX interpreter)
  • create a WPS Object for the REXX program STARTCR.CMD with the following setup
Title Start Classic REXX
Path and filename *
Parameters /K .\STARTCR.CMD
Working directory the directory with STARTCR.CMD

Now you can select the REXX interpreter to use:

Start the WPS object "Start Classic REXX" if you need Classic REXX or start the WPS object "Start Object REXX" if you need Object REXX. All other programs started after one of these objects will use the REXX interpreter that is loaded.

Note that it is only possible to use one REXX interpreter at a time. To switch the REXX interpreter either from Classic REXX to Object REXX or vice versa, you must first close all sessions using REXX, wait a bit and start the WPS object using the other REXX interpreter. Note also, that you must unload all DLLs using REXX (for example REXXUTIL.DLL) before switching the interpreter.

And last:

Please be aware that this method does not work in all cases!

/* STARTCR.CMD                                                      */
/* sample REXX cmd to start a session using Classic REXX if OO REXX */
/* is the default REXX interpreter                                  */
/*                                                                  */
/* To use this cmd you must                                         */
/* - ensure that your LIBPATH contains the entry '.;' before the    */
/*   entry \OS2\DLL                                                 */
/* - copy the REXX.DLL from Classic REXX into the directory with    */
/*   this CMD                                                       */
/* - create an Object for this CMD with                             */
/*   Path and filename = *                                          */
/*   Parameters = /K .\STARTCR.CMD                                  */
/*   Working directory: the directory with this program             */
/* - ensure that no other session using REXX is running             */
/*                                                                  */
/* Usage: STARTCR [startDir]                                        */
/*                                                                  */
/* Where: startDir = working directory to use                       */
/*                   Def.: use directory with STARTCR.CMD           */
/*                                                                  */
  parse arg StartDir

  say
  say
  say 'Starting a CMD session using the Classic REXX interpreter ...'
  say
  parse version interpreterVersion rest
  say 'The current REXX Interpreter version is ' || ,
      interpreterVersion rest

  if interpreterVersion <> 'REXXSAA' then
  do
    say '07'x
    say 'Error: Cannot load the DLL with the Classic REXX interpeter!'
    say
    say 'Hint:  Close all sessions using REXX, wait a minute and try'
    say '       again.'
    say
    '@pause'
    'exit'
  end /* if */
  else
  do
    if StartDir <>  then
      call directory StartDir
    say 'Current working directory is "' || directory() || '".'
    say
  end /* else */
exit 0

(see also How to switch from Classic REXX to Object REXX and vice versa)

Using Object REXX and the WPS

It seems that the WPS part of Object REXX never finishes its initialisation part and therefore has to be forced to do so to use the WPS classes in Object REXX programs. You can force the finishing of the initialisation by opening the Template folder for example - but that's no general solution of course.

To test if this bug occurs on your system, simply issue the command

 rexxtry say .wps

If the output is .WPS then the error occurs on your system.

As a workaround to the WPS Server not getting initialized, you can put a program object with the following settings in your startup folder:

Program = c:\os2\wpsinst.cmd
Parameter = +

This may help ensure that the WPS part of Object REXX finishes its initialisation at startup (note that not all who have tried this have reported success).

[Fixed in OBJREXX 6.00 25 Mar 1998 and newer versions]

It seems that the WPS part of Object REXX is incompatible with some other WPS Extensions, for example Object Desktop. In this case, you must decide either to use the WPS part of Object REXX or the WPS Extension.

To use Object REXX with Object Desktop you only need to deinstall the "Enhanced Folder" Component of Object Desktop - that's the only part of Object Desktop that is affected by Object REXX.

If you want to keep Object Desktop's Enhanced Folder on your desktop, all you need to do is to NOT install the WPS classes of Object REXX (these are the classes initialized by the wpsinst.cmd program). Object REXX will still be loaded, and you'll still have access to all Object REXX commands, except the ones involving the new classes.

Writing OS-independent programs in Object REXX

If you want to write operating system independent programs using Object REXX, you should keep the following differences between Object REXX for OS/2 and Object REXX for Windows 95 / Windows NT in mind:

  • in the Windows version, the environment is process-local
  • in the Windows version, host commands are executed in a new process
  • on Windows 95, host commands always return 0
  • Object REXX on Windows does not support SOM, and the DBCS support is not documented
  • in both versions (Win95 and OS/2) you should use VALUE( envVarName, envVarValue, 'ENVIRONMENT' ) to set or read environment variables
  • in both versions (Win95 and OS/2) you should use VALUE( envVarName, .NIL, 'ENVIRONMENT' ) to delete an environment variable

More information about Object REXX for the Windows platform can be found at the Object REXX home page (see Internet - Web Pages).

Adding Object REXX Support to a maintenance partition

To add Object REXX to a maintenance partition (created with BOOTOS2 for example) do the following:

  1. Create the maintenance partition without REXX support. (In the statements below I assume that F: is the drive letter for the maintenance partition)
  2. Create a new directory on the maintenance partition (e.g. F:\OREXX)
  3. Add the new directory to the PATH, LIBPATH and DPATH statement in the file F:\CONFIG.SYS
  4. Copy the following files from your existing OS/2 partition with activated Object REXX support to the new directory F:\OREXX:
    OS2\DLL\NAMEREXX.DLL
    OS2\DLL\PMREXXIO.DLL
    OS2\DLL\REXX.DLL
    OS2\DLL\REXXAPI.DLL
    OS2\DLL\REXXCRT.DLL
    OS2\DLL\REXXINIT.DLL
    OS2\DLL\REXXSC.DLL
    OS2\DLL\REXXSOM.DLL
    OS2\DLL\REXXUTIL.DLL
    OS2\DLL\REXXWPS.DLL
    OS2\DLL\SOMD.DLL
    OS2\DLL\SOMSEC.DLL
    OS2\DLL\SOM.DLL
    OS2\DLL\SOMEM.DLL
    OS2\DLL\SOMIR.DLL
    OS2\DLL\SOMS.DLL
    OS2\DLL\SOMTC.DLL
    OS2\DLL\SOMU.DLL
    OS2\DLL\SOMUC.DLL
    OS2\SYSTEM\REX.MSG
    OS2\SYSTEM\REXH.MSG
    OS2\REXXTRY.CMD
    OS2\PMREXX.EXE
    OS2\REXXC.EXE
    OS2\REXX.ICO
    OS2\REXX.IMG
    OS2\WPREXX.IMP
  5. Copy the file BOS2REXX.EXE from the BOOTOS2-Package to the new directory.
  6. Add the line RUN=F:\OREXX\BOS2REXX.EXE to the file F:\CONFIG.SYS
  7. Reboot from the maintenance partition and test the REXX support (for example with REXXTRY)