Jump to content

REXX Tips & Tricks:General hints for REXX: Difference between revisions

From EDM2
Line 801: Line 801:


1. Method
1. Method
Start the program from within a PM program (like EPM) or use the program �PMREXX to start the REXX program. (see also Run a REXX program under a specific environment)
Start the program from within a PM program (like EPM) or use the program PMREXX to start the REXX program. (see also Run a REXX program under a specific environment)


You can also use one of the visual REXX development tools for the REXX program (like VX-REXX, VisPro/REXX or GpfREXX; see also the REXX development tools & extensions listed in the section PM Tools). These environments normally provide better PM controls than RxMessageBox().
You can also use one of the visual REXX development tools for the REXX program (like VX-REXX, VisPro/REXX or GpfREXX; see also the REXX development tools & extensions listed in the section PM Tools). These environments normally provide better PM controls than RxMessageBox().
Line 813: Line 813:


3. Method
3. Method
Create an object with PROGTYPE set to PM for the REXX program and use the function �SysOpenObject or �SysSetObjectData to start the program:
Create an object with PROGTYPE set to PM for the REXX program and use the function SysOpenObject or SysSetObjectData to start the program:


<PRE>  
<PRE>  

Revision as of 03:18, 5 November 2012

This section contains general hints for REXX under OS/2.

Another good source for REXX related information is the Web pages of Quercus System--in particular, the pages How do I ... and Common REXX Pitfalls (see Internet - Web Pages)

You should also take a look at the REXX FAQ maintained by Dave Martin (see Internet - Web Pages).

REXX and Y2K

The latest FixPaks for OS/2 Warp 3 (FP35 and above) and Warp 4 (FP6 and above) contain extensions for REXX to make it "Y2K Tolerant".

From a recent FixPak's Readme:


  4.1 QUERYING FILE DATES FOR FILES AFTER DEC 31, 1999 IN REXX

     Existing REXX functions return file dates with a two digit year
     only. While these functions are Year 2000 tolerant (i.e. the
     results will be correct for files dated after Dec 31, 1999)
     they require some additional logic in existing programs to
     handle the returned date correctly when they are compared with
     other file dates.

     Since the output format of the exisiting functions could not
     be changed for compatibility reasons, new options have been
     added to the REXX interpreter to return file dates with the
     year formatted with 4 digits. Two functions have been
     extended to support the new format. The syntax to retrieve the
     file date in 4 digit format is as follows:

     /********************************************/
     /* Use STREAM QUERY TIMESTAMP to query file */
     /* date in 4 digit format                   */
     /********************************************/

     Say Stream("C:\CONFIG.SYS", "C", "QUERY TIMESTAMP")

     /***********************************************/
     /* Use option "L" with SysFileTree to return a */
     /* list of files with long date format         */
     /***********************************************/

     Call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs"
     Call SysLoadFuncs
     Call SysFileTree "C:\*.*", "Files", "L"
     Do i = 1 To Files.0
        Say Files.i
     End /* do */

Reserved Words

"REXX has no reserved words. Words are only reserved in context. Hence:


 if=1

 if if then
   then=2;
 else
   else=7

 do forever=3 to 7 until end;
   end=1;
 end

parse var x with var with left right value

are all valid instructions. A function is recognised solely by the presence of a '(' appearing immediately after it, not by the spelling of its name.

This is where Rexx has a big advantage over things like Visual BASIC. (I was typing a BASIC program the other day, and the first three variable names I tried were all keywords...)"

Source: Ian Collier

Using comments

Although it's possible to use multi-line comments in REXX programs, it's not advisable. Multi-line comments can make it very difficult to search an error in REXX programs.

Note: Because nested comments are allowed in REXX, you should use the following technique to use the strings to mark the beginning and the end of a comment in a string:

"/" || "*"

and

"*" || "/" 

Writing OS independent programs

To write OS independent REXX programs, you can use the �PARSE SOURCE statement to distinguish between the different platforms (see example below and the chapter about PARSE SOURCE. The chapter titled Force a REXX program to run in a special way also discusses the use of PARSE SOURCE to identify the environment in which a REXX program is running and then process conditional commands.

When writing programs for use on other platforms in addition to OS/2, remember that some of the features and functions in OS/2 REXX are not implemented in REXX on other platforms (or may be implemented in a different manner)!

(see REXXTRY.CMD for another example for OS independent REXX programs)

/* ------------------------------------------------------------------ */
/*                                                                    */
/* APPLICATION - Cross Platform - CMS, OS/2 2.0 and TSO               */
/* FUNCTION    - Merge 4 comma-delimited input files into an          */
/*               outputfile, tagging each record with the name of     */
/*               it's corresponding input file                        */
/* USE:   OS/2 - MERGE f1.ext,f2.ext,f3.ext,f4.ext,outfile.ext        */
/*        TSO  - MERGE f1.qlf,f2.qlf,f3.qlf,f4.qlf,outfile.qlf        */
/*        CMS  - MERGE fn1 ft1 fm1,fn2 ft2 fm2,...fm4,ofn oft ofm     */
/* AUTHOR      - Michel Plungjan April '93                            */
/*               (see EMail Addresses)                                */
/*                                                                    */
/* History:                                                           */
/*  12.12.1995 /bs                                                    */
/*    - reformatted and added some comments                           */
/*  26.02.1996 /bs                                                    */
/*    - corrected a bug in the TSO read secition according to         */
/*      information from Michel Plungjan                              */
/*                                                                    */
/* ------------------------------------------------------------------ */

  arg InFile.1 "," InFile.2 "," InFile.3 "," InFile.4 "," Merged

  if InFile.1 = "/?" then
    signal HELP;

  call INIT

  j = 0;
  do i = 1 to 4
    FileName = Infile.i
    call READFILE;
    if InRec.0 > 0 then
    do k = 1 to InRec.0
      j = j + 1
      OutRec.j = strip(InRec.k,"T") substr(FileName,1,4)
    end; /* do k = 1 to InRec.0 */
  end; /* do i = 1 to 4 */

  if j > 0 then
  do
    OutRec.0 = j;
    call WRITEFILE;
  end /* if j > 0 then */
  else
  do
    XReason = "Input files empty...";
    XRc = 8;
    SIGNAL ABNORMAL_END
  end; /* else */

SIGNAL NORMAL_END;

/* ------------------------------------------------------------------ */
/*                                                                    */
READFILE:
  select

    when sys = 'CMS' then
    do

/* --------------------- code for CMS ------------------------------- */

      'EXECIO * DISKR' FileName '(FINIS STEM INREC.'
       hrc = rc
       if hrc <> 0 then
       do
         XRc = hrc
         XReason = 'Error when reading' FileName 'dataset'
         SIGNAL ABNORMAL_END
       end /* if hrc <> 0 then */
    end /* CMS */

    when sys = 'TSO' then
    do

/* --------------------- code for TSO ------------------------------- */

      'ALLOC DA('FileName') FI(INDD) SHR'
      hrc = rc
      if hrc <> 0 then
      do
        XRc = hrc
        XReason = 'Allocation error of' FileName 'dataset'
        SIGNAL ABNORMAL_END
      end
      'EXECIO * DISKR INDD (FINIS STEM INREC.'              /* v2.10 */
      hrc = rc
      if hrc <> 0 then
      do
        XRc = hrc
        XReason = 'Error when reading' FileName 'dataset'
        SIGNAL ABNORMAL_END
      end /* if hrc <> 0 then */
      'FREE FI(INDD)'
      hrc = rc
      if hrc <> 0 then
      do
        XRc = hrc
        XReason = 'Error when freeing' FileName 'dataset, DDName INDD'
        SIGNAL ABNORMAL_END
      end /* if hrc <> 0 then */
    end /* TSO */

    when sys = 'OS/2' then
    do

/* --------------------- code for OS/2 ------------------------------ */

      do ii = 1 while lines(filename) > 0
        InRec.ii = linein(FileName)
      end; /* do ii = 1 while lines( fileName) > 0 */

      InRec.0 = ii - 1
      if (stream(FileName,'S') <> 'READY') then
      do
        XRc = 1
        XReason = 'Error when reading' InFile ,
                  'file, Error indicator is 'stream(FileName,'D')
        SIGNAL ABNORMAL_END
      end /* I/O Error */
    end /* OS/2 */

    otherwise
    do

/* --------------------- unknown OS --------------------------------- */

      XReason = 'This program does not know how the environment' sys,
                'uses I/O, please contact author'
      XRc = 8
      SIGNAL ABNORMAL_END
    end /* otherwise */

  end /* Select */
return

/* ------------------------------------------------------------------ */
/*                                                                    */
WRITEFILE:

  select

    when sys = 'CMS' then
    do

/* --------------------- code for CMS ------------------------------- */

      'EXECIO 'OutRec.0 'DISKW 'Merged '0 F 80 (FINIS STEM OUTREC.'
      hrc = rc
      if hrc <> 0 then
      do
        XRc = hrc
        XReason = 'Error when writing' Merged 'dataset'
        SIGNAL ABNORMAL_END
      end /* if hrc <> 0 then */

    end /* CMS */

    when sys = 'TSO' then
    do

/* --------------------- code for TSO ------------------------------- */

      'ALLOC DA('Merged') FI(OUTDD) SHR' /* File must already exist */
      hrc = rc
      if hrc <> 0 then
      do
        XRc = hrc
        XReason = 'Allocation error of' Merged 'dataset'
        SIGNAL ABNORMAL_END
      end /* if hrc <> 0 then */

      'EXECIO' OutRec.0 'DISKW OUTDD (FINIS STEM OUTREC.'
      hrc = rc

      if hrc <> 0 then
      do
        XRc = hrc
        XReason = 'Error when writing' Merged 'dataset'
        SIGNAL ABNORMAL_END
      end /* if hrc <> 0 then */

      'FREE FI(OUTDD)'
      hrc = rc
      if hrc <> 0 then
      do
        XRc = hrc
        XReason = 'Error when freeing' Merged 'dataset, DDName OUTDD'
        SIGNAL ABNORMAL_END
      end /* if hrc <> 0 then */

    end /* TSO */

    when sys = 'OS/2' then
    do

/* --------------------- code for OS/2 ------------------------------ */

      do i = 1 to OutRec.0
        Dummy = lineout(Merged,OutRec.i);
      end; /* do i = 1 to OutRec.0 */

      rc = stream(Merged,'c','close')

      /* please put your own OS/2 error checking here */
    end /* OS/2 */

    otherwise
    do

/* --------------------- unknown OS --------------------------------- */

      XReason = 'This program does not know how the environment' sys,
                'uses I/O, please contact author'
      XRc = 8
      SIGNAL ABNORMAL_END
    end /* otherwise */

  end /* Select */
return;

/* ------------------------------------------------------------------ */
/* init global variables and get the current OS (in the var SYS)      */
/*                                                                    */
INIT:
  true  = 1;
  false = 0;
  XReason = 'Files merged, you may now sort the file 'Merged;
  XRc = 0
  parse source sys .
return

/* ------------------------------------------------------------------ */
/* show the usage help                                                */
/*                                                                    */
HELP:
  do i = 1 until pos('* ---',sourceline(i)) > 0
    say strip(sourceline(i))
  end /* do i = 1 ... */
exit;

/* ------------------------------------------------------------------ */
/*                                                                    */
ABNORMAL_END:
  say 'Program stopped due to'

/* ------------------------------------------------------------------ */
/*                                                                    */
NORMAL_END:
  say XReason 'return code:' Xrc
exit

Writing filter programs in REXX

Filter programs are programs that read from standard input, convert the input in some way, and write the converted lines to standard output. Filter programs are heavily used in UNIX systems, but you can use them on any operating system supporting redirection of standard input and standard output with pipes, for example, OS/2.

In OS/2 you can write filter programs very simply in REXX (see the example below). But you should take care to be aware of the following points:

Write all messages (error messages, logos, etc.) to STDERR instead of STDOUT, e.g. use

 call LineOut "STDERR", "This is an error message"

(see also Using the handles 3 to 9 in REXX programs)

Always use

 call trace "OFF"

as first statement in a filter program (after the required REXX comment delimiters on line 1, of course). This statement makes sure that your program ignores the environment variable RXTRACE.

Also be aware that the function LINES() does not work as expected in Object-Oriented REXX (see The function LINES() in Object REXX). Therefore, you must distinguish between the different REXX versions in your filter program.

see General input line enhancer for a special filter program

/* ------------------------------------------------------------------ */
/* Simple filter program in REXX                                      */
/*                                                                    */
/* A filter program reads lines from STDIN, does something with them, */
/* and writes the changed lines to STDOUT                             */
/*                                                                    */
/* In this example we simply convert the lines to uppercase.          */
/* This program works for Classic REXX and for Object REXX.           */
/*                                                                    */

  call trace "OFF"

  signal on notready name ProgramEnd

                    /* check the REXX interpreter version             */
  parse version rexxVersion .
  if rexxVersion = "OBJREXX" then
  do;
                    /* current REXX version is Object REXX            */

                    /* main loop for Object REXX                      */
                    /* (The loop is aborted by a NOTREADY condition)  */
    do forever
      .output~lineout( convert( .input~linein ) )
    end /* do forever */

  end /* if rexxVersion = "OBJREXX" then */
  else
  do
                    /* current REXX version is Classic REXX           */

                    /* main loop for Classic REXX                     */
    do while lines( "STDIN" ) <> 0
      call lineOut "STDOUT", convert( lineIn( "STDIN" ) )
    end /* do while lines() <> 0 */

  end /* else */

programEnd:

exit 0

/* ------------------------------------------------------------------ */
/* this function returns the parameter in uppercase                   */
/*                                                                    */
Convert: PROCEDURE
  parse arg inputLine
  return translate( inputLine )

Using the handles 3 to 9 in REXX programs

OS/2 defines 10 general file handles for batch files (and therefor also for REXX programs):

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³Handle         ³Default assignment                           ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³0              ³Standard Input (STDIN)                       ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³1              ³Standard Output (STDOUT)                     ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³2              ³Standard Error (STDERR)                      ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³3              ³no default assignment                        ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³4              ³no default assignment                        ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³5              ³no default assignment                        ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³6              ³no default assignment                        ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³7              ³no default assignment                        ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³8              ³no default assignment                        ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³9              ³no default assignment                        ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

To use the handles 0 to 2 in REXX programs, use the filenames STDIN, STDOUT, or STDERR. Note that these are the default values and therefor you do not have to explicitly code them. The handles 0 to 2 always exist and point either to the keyboard (handle 0), the screen (handles 1 and 2), or to a file if redirected via <, >, or |.

It's also possible to use the handles 3 to 9 in REXX programs. To do that, you must call the program with a redirection for the handle and inside the REXX program you can access them only via OS/2 commands, like for example the �ECHO command.

Examples:

Example for using ony the handle 3:

/* testHandle3.cmd                                                    */
/*                                                                    */
/* REXX sample on using handle 3 in a REXX program                    */
/* call this cmd with                                                 */
/*                                                                    */
/*   testHandle3.cmd 3>handle3.out                                    */
/*                                                                    */

  testString = "This text goes to the file referenced by handle 3"
  "echo. " testString ">>&3"
exit 0

Example for using the handles 3 to 9:

/* testHandles3to9.cmd                                                */
/*                                                                    */
/* REXX sample on using the handles 3 to 9 in a REXX program          */
/* call this cmd with                                                 */
/*                                                                    */
/*   testHandles3to9.cmd 3>ha3 4>ha4 5>ha5 6>ha6 7>ha7 8>ha8 9>ha9    */
/*                                                                    */

  testString = "This text goes to the file referenced by handle "
  do i=3 to 9
    "echo. " testString || i ">>&" || i
  end /* for */
exit 0

You can also redirect more then one file handle into a file. Example:

 testhandles3to9.cmd 3>test3x.out 4>>&3 5>>&3 6>>&3 7>>&3 8>>&3 9>>&3

In this example every echo command writes to the file test3x.out.

 testhandles3to9.cmd 3>test3x.out 4>>&3 5>>&3 6>>&3 7>>&3 8>>&3 9>>&3 3>test3y.out

In this example every echo command except the echo command for handle 3 writes to the file test3x.out. The echo command for handle 3 writes to test3y.out

Please be aware that the output goes to STDOUT or you will get an error message if you try to use an unassigned file handle - for example if you call the first example testHandle3.cmd above without the redirection of the handle 3:

   testHandle3.cmd

Also be aware that files you open inside your REXX program will get the next free file handle. Therefor the first file you open in a REXX program normally gets the handle 3. But if you redirect the handle 3 into a file via redirection on the command line the first file you open inside your REXX program will get the handle 4. Try the example below to see the difference.

/* testHandle3a.cmd                                                   */
/*                                                                    */
/* REXX sample                                                        */
/*                                                                    */
  call stream 'TESTSTREAM', 'c', 'OPEN WRITE'

  testString = "This text goes to the file referenced by handle 3"
  "echo. " testString ">>&3"

  call stream 'TESTSTREAM', 'c', 'CLOSE'
exit 0

If you call this program with

   testHandle3a.cmd 3>handle3.out

the output goes to the file HANDLE3.OUT. if you call this example with

   testHandle3a.cmd

the output goes to the file TESTSTREAM.

To check if one or more of the handles 3 to 9 are redirected to a file, you can check which handle you'll get if you create a new file:

/* This code works in Object-Oriented REXX only!                      */
  DATAFILE = 'NUL'
  if stream( DATAFILE, 'c', 'OPEN READ' ) = "READY:" then
  do
    DATAFILE_handle = stream( DATAFILE, 'c', 'QUERY HANDLE' )
    say "DATAFILE handle is" DATAFILE_handle
    call stream DATAFILE, 'c', 'CLOSE'
  end /* if */
  else
    say "Error opening " || DATAFILE || " for reading!"

Normally, if the handles between 3 and 9 are not redirected, the handle for the new file is 3. If one or more of the handles 3 to 9 is redirected to a file the handle you get is 5 (if only handle 3 is redirected), 6 (if handle 3 and 4 are redirected), and so on.

BUT

The handle is also 5 or above if STDIN, STDOUT, or STDERR is redirected to another device, file or pipe. So, to be sure, check this also (How to check if STDIN, STDOUT or STDERR are redirected to a file) a

see Using redirection for a simple process controller, General input line enhancer for other samples. see Output & Input control, Reserved names for files in REXX for additional information.

Calling REXX programs in the CONFIG.SYS

You can call REXX programs in the CONFIG.SYS file by using the CALL statement. To do this, load the REXX support with (for example) BOS2REXX.EXE prior to the line that calls your REXX program in CONFIG.SYS.

Example:

 REM *** load the REXX support
 RUN=E:\OS_2\tools\bootos2\bos2rexx.exe

 REM *** call the REXX program
 CALL=C:\OS2\CMD.EXE /C myprog.cmd

Note that you can only use the non-WPS related functions from REXXUTIL.DLL in programs called in the CONFIG.SYS. Note further, that you must use �RxFuncAdd to load each necessary REXXUTIL function by hand -- you cannot use �SysLoadFuncs! See the next chapter for an example for using this technique.

(see also the important note at the end of the section Using REXX if booted from diskette and RxFuncAdd)

Example for using REXX programs in the CONFIG.SYS

A REXX program called from within the CONFIG.SYS is always called after loading all drivers. So, if you want to use a REXX program to change one or more DEVICE or BASEDEV statements (or a file used by a device driver) in the CONFIG.SYS while booting the workstation, you must use a 2-step-method.

Here's an example: Some time ago a CompuServe forum member said he wanted to change the file PROTOCOL.INI in respect to the input of an user while OS/2 was booting. (PROTOCOL.INI is an ini file used by a device driver necessary for the Network support).

I suggested to call the REXX program below in the CONFIG.SYS for this purpose (see Calling REXX programs in the CONFIG.SYS on how to call a REXX program in the CONFIG.SYS). This program uses a status file and an additional boot process to change the configuration on the fly.

The advantage of this method in contrast with using OS/2's ALT-F1 feature to perform maintenance at bootup:

It runs not only on WARP 3, but also under OS/2 versions prior to WARP; there's no overhead and you only have to maintain one configuration.

(see RxFuncAdd if you want to use other DLLs in a REXX program called in the CONFIG.SYS)

/* REXX program which can be called in the CONFIG.SYS to get some     */
/* input from the user, check the current configuration against the   */
/* user input, and change the configuration and reboot the            */
/* workstation with the changed configuration if necessary.           */
/*                                                                    */
/* Note that you can use this method also to change some lines in     */
/* your CONFIG.SYS.                                                   */
/* Note further, that you can also replace the code to get the user   */
/* input with some code to automatically get the needed configuration.*/
/*                                                                    */
/* You can also use the routine Getkey in programs called in the      */
/* CONFIG.SYS.                                                        */
/*                                                                    */
/* (c) 1996 Bernd Schemmer, Germany, EMail: Bernd.Schemmer@gmx.de     */
/*                                                                    */

                    /* install an error handler for user breaks       */
  SIGNAL ON HALT Name UserBreak

                    /* name of the status file for the current boot   */
                    /* process. If this file exists, this is the      */
                    /* second boot, if not it's the first.            */
  statusFile = "C:\BOOTSEM"

  if stream( statusFile, "c", "QUERY EXISTS" ) = "" then
  do
                    /* first boot                                     */

                    /* load the necessary REXXUTIL function(s). Note  */
                    /* that you CANNOT use SysLoadFuncs!!!            */
    call rxFuncAdd "SysGetKey", "REXXUTIL", "SysGetKey"

                    /* get the user input                             */
    call CharOut, "Which PROTOCOL.INI do you want? Press A or B ->> "
    do forever
      userInput = translate( SysGetKey( "NOECHO" ) )
      if UserInput = "A" | UserInput = "B" then
        leave
      else          /* invalid user response - ring the bell          */
        call CharOut , "07"x
    end /* do forever */

    call LineOut , UserInput


                    /* check the configuration, in this example:      */
                    /* check if the existing PROTOCOL.INI is correct  */
    call LineOut , "Checking the configuration. Please wait ..."

                /* ... insert the code to check the configuration ... */
                /* set ConfigurationOK to 1 if PROTOCOL.INI is okay   */

    if ConfigurationOK = 1 then
    do
                    /* the current configuration is okay              */
                    /* continue with the boot process                 */

      call LineOut, "The current configuration is okay." ,
                    "Boot process continues ..."

    end /* if ConfigurationOK = 1 then */
    else
    do
                    /* the current configuration is NOT okay          */

      call LineOut, "The current configuration is NOT okay." ,
                    "Now changing the configuration ..."


                    /* correct the configuration, in this example:    */
                    /* replace the PROTOCOL.INI                       */

                /* ... insert the code to change the configuration ...*/

                    /* now create the status file                     */
      call LineOut statusFile, "We need a second boot ..."

                    /* close the status file                          */
     call stream statusFile, "c", "CLOSE"

     call LineOut, "Rebooting your workstation please wait ..."

                    /* and reboot the workstation using SETBOOT       */
     "SETBOOT /IBD:C"

    end /* else */
  end  /* if stream( statusFile, "c", "QUERY EXISTS" ) = "" then */
  else
  do
                    /* second boot                                    */

                    /* normally nothing to do because the             */
                    /* configuration should now be okay               */
  end /* else */

                    /* delete the status file also on user breaks     */
UserBreak:

                    /* delete the status file if it exists            */
  if stream( statusFile, "c", "QUERY EXISTS" ) <> "" then
    "@del " statusFile "2>NUL 1>NUL"

Using REXX if booted from diskette

When OS/2 is booted from diskette, you must use a special program to load the REXX support (normally, OS/2 boots from the hard disk and the WPS loads REXX support automatically).

The best program available to load REXX from diskette is BOS2REXX.EXE.

To create a boot diskette with REXX support do the following:

  • Create a boot diskette with, for example BOOTOS2.
  • Copy BOS2REXX.EXE to the boot diskette
  • Add the statement RUN=A:\BOS2REXX.EXE to the file A:\CONFIG.SYS
  • Add the directory with the files REXX*.DLL (\OS2\DLL) to the �LIBPATH in the file A:\CONFIG.SYS
  • Add the directory with the file REX.MSG (\OS2\SYSTEM) to the �DPATH in the file A:\CONFIG.SYS

Note: You may omit the third step. In this case you must init the REXX support manually with the command

  �detach A:\BOS2REXX.EXE

This method allows you to load REXX support only if necessary.

  • see also Using REXXUTIL; use LX lite - an compressor for OS/2 executables to create one (!) boot diskette with REXX support and other useful tools!)

Important: Do NOT kill the process with BOS2REXX! Your REXX programs might not act as expected if you do so! The process which initially starts the REXX support is required throughout the session because it handles the global data, semaphores and so on. This is true even if you restart BOS2REXX after killing it!

Source: APAR PJ15496

  • see also Adding Object REXX Support to a maintenance partition and RxFuncAdd)

Force a REXX program to run in a special way

Sometimes it is important for a REXX program to run within a specific environment (e.g. PMREXX) or in a special way (e.g. minimized or in the background).

To ensure that your REXX program uses the environment you intend it to use, you can check the current environment in your REXX program and, if it's not the envionment you need, restart the REXX program in the needed environment:

In the first case mentioned above, you can use the return code of the function �ADDRESS to check the current environment (see Run a REXX program under a specific environment and the warning regarding WARP 4 in the section PMREXX!); in the second case (i.e., running your program in a special way, such as minimized), you cannot detect the current environment and thus you've to restart your program using an additional parameter to distinguish between the two passes. (see Force a REXX program to run minimized).

Run a REXX program under a specific environment

Use the return code of the function �ADDRESS to force a REXX program to run under a specific environment:

/* ------------------------------------------------------------------ */
/* sample prolog to force a REXX program to run under a specific      */
/* environment.                                                       */
/*                                                                    */
/* In this example we force the program to run under PMREXX           */
/*                                                                    */
/* (see also Force a REXX program to run minimized and the warning    */
/* in the section PMREXX)!                                            */
/*                                                                    */

                        /* name of the needed environment (return     */
                        /* code of the function �ADDRESS)             */
  neededEnvironment = "PMREXX"

                        /* program to call to setup the correct       */
                        /* environment                                */
  executor = "PMREXX.EXE"

                        /* check the address environment              */
  if address() <> neededEnvironment then
  do
                        /* THIS part is only executed if NOT running  */
                        /* under the needed environment               */

                        /* get the name of this program               */
    parse source . . thisProg

                        /* now call the program again using the       */
                        /* defined program to setup the environment   */
    "start " executor  thisProg arg(1)

    exit rc
  end /* if adress() <> neededEnvironment then */

                        /* THIS part is only executed if we are       */
                        /* running under the needed envrionment!      */
  call RxMessageBox "This program was forced to run under PMREXX",,
                    "This is a test message"

exit 0

Force a REXX program to run minimized

Use the following method to force a REXX program to run in a special way (e.g. minimized, in the background, in a full screen session, ...)

/* sample prolog for a REXX program to run minimized                  */
/* (see also Run a REXX program under a specific environment)         */

                    /* turn CTRL-BREAK OFF                            */
  signal off halt

                    /* get the name of this file                      */
  parse source . . thisFile

                    /* get the parameter                              */
  parse arg thisParameter

                    /* check the pass of this file                    */
  pass2Parameter = "$$PASS2$$"

  if word( thisParameter,1 ) <> pass2Parameter then
  do
                    /* this is the first pass: restart the            */
                    /* CMD minimized                                  */
     address "CMD" "start /C /MIN /BG cmd /c " ,
                     thisFile pass2Parameter thisParameter

                    /* and end the program                            */
     exit

  end /* if */

                    /* this is the second pass: cleanup the parameter */
                    /* and continue                                   */
  parse var thisParameter (pass2Parameter) thisParameter

  /* !!! insert your code here !!! */
exit

Start a REXX program in PM mode

To start a REXX program in a PM environment there are at least three methods available (note that a REXX program must run in a PM environment to use the function RxMessageBox()):

1. Method Start the program from within a PM program (like EPM) or use the program PMREXX to start the REXX program. (see also Run a REXX program under a specific environment)

You can also use one of the visual REXX development tools for the REXX program (like VX-REXX, VisPro/REXX or GpfREXX; see also the REXX development tools & extensions listed in the section PM Tools). These environments normally provide better PM controls than RxMessageBox().

2. Method Start the REXX program with the following command:

start /pm cmd /c {programPath}programName

Note that this is not possible in 4OS2 sessions!

3. Method Create an object with PROGTYPE set to PM for the REXX program and use the function SysOpenObject or SysSetObjectData to start the program:

 
/* REXX code to create a WPS object to start the REXX program         */
/*   C:\TESTPM.CMD                                                    */
/* in a PM environment (assuming OS/2 is installed on drive C:)       */

                    /* load the necessary REXXUTIL functions          */
  call rxFuncAdd "SysLoadFuncs", "REXXUTIL", "SysLoadFuncs"
  call SysLoadFuncs

                    /* create the object                              */
  if SysCreateObject( ,
      "WPProgram"                               ,, /* object class    */
      "REXX program in a PM environment"        ,, /* object title    */
      "<WP_DESKTOP>"                            ,, /* object location */
      "EXENAME=C:\OS2\CMD.EXE;"            || ,    /* object setup    */
      "PROGTYPE=PM;"                       || ,    /*  string         */
      "PARAMETERS=/C C:\TESTPM.CMD;"       || ,
      "OBJECTID=<MyObject>;"                    ,, /* replace flag    */
      "U" ) = 1 then
  do
                    /* execute the program (all OS/2 version, you can */
                    /* also use SysOpenObject in OS/2 WARP)           */
    call SysSetObjectData  "<MyObject>", "OPEN=DEFAULT";

  end /* if SysCreateObject( ... */