[Access to Wang masthead]

The $VERIFY Procedure

Using subprocedures

From "VS Procedure",  Access 87, February 1987
  [ Prior Article ]     [ Return to the Catalog of articles ]     [ Next Article ]  

In any installation, there are tasks that must be performed many times. Examples include special input and output methods, date checking routines, etc. A good way of handling these needs is through subprocedures.

A subprocedure is a procedure that acts as a SUBROUTINE; that is, it accepts data from a program or procedure, processes that data, and returns to the point of origin. A subprocedure usually produces no visible product; instead, it performs a generic process for a program or procedure, such as checking for the existence of a file and invoking system utilities.

Like program subroutines, subprocedures allow the programmer to do much more by eliminating need to code and test some standard procedure sections. With relief from much of the drudgery of coding and testing repetitive sections, the programmer is free to pursue the primary task without distractions.

The key concept here is that a subprocedure ACCEPTS DATA AND PROCESSES IT. Deciding how the data will be processed within the subprocedure is usually the easy part; you already have a problem and are seeking a solution. Choosing how the subprocedure will receive the data is somewhat more complicated. As with many other aspects of programming, there are several approaches.

Passing information between procedures

In all cases, some information must be exchanged between the calling program or procedure and the subprocedure. This information might be either data or control information. Data is the actual information to be processed; control information tells the calling program or procedure the status of the data after processing. Either form of information can be sent by either PASSING ("sending") a list of variables or by defining GLOBAL variables in the calling procedure.

The most straightforward method of sending data to a subprocedure is to pass a series of variables within a USING clause. In programming jargon, these variables are known as arguments. This approach requires that the arguments passed from the controlling program or procedure exactly match the expected number, type, and length in the subprocedure; any deviation results in an error. Note that a subprocedure using this approach to data handling may be called by a program as well as another procedure.

The second approach - using GLOBAL variables - is unique to Procedure language. Unlike other local variables, a global variable exists in all procedures run below the procedure defining them, not just in the primary procedure. You define a global variable once, use it in subsequent processes, and receive the contents of the variable after any changes. The primary advantage of this approach is that there is no requirement to match the arguments passed to those expected by the subprocedure. The primary disadvantage is lessened clarity and the inability to return information to a program rather than a procedure.

Example: TRACER revised to use $VERIFY

As an example of both approaches to linking, here are some minor revisions to last month's procedure, TRACER. You may have noticed that TRACER does not check whether the file names you type in are valid; thus, it is quite possible to type in a file, library, or volume name that is illegal. I discovered this omission the hard way! After that unfortunate experience, I added a standard file-name check subprocedure, $VERIFY, to check the validity of the file, library, and volume name entered. Here is how I modified TRACER to use this subprocedure (see Figure 1):

1. Change the DECLARE statement for the variable &MESSAGE to GLOBAL. This means that &MESSAGE may be used by $VERIFY.

2. Change steps @0 through S02 to run the $VERIFY subprocedure. Note that the file, library, and volume names must be passed between the procedures, but the names do not need to be the same. For example, the contents of &INFIL are used within $VERIFY within the local variable &TESTFIL, then returned within &INFIL).

3. Provide a means for testing the &MESSAGE field after $VERIFY completes its run. If &MESSAGE returns with a message, there has been an error requiring user attention.

I use &MESSAGE as a variable name within most procedures. I chose to define it as a global variable so that I could continue to use it in whatever length I choose in the calling procedure. Similarly, I chose to pass the file, library, and volume names through the USING clause so that I wouldn't have to define the same variable names in every procedure.

Using subprocedures in your shop

You can put subprocedures to work today. Begin by studying the tasks you normally perform within procedures, trying to see what is common among them. Try a few subprocedures at a time, testing carefully. Be sure to keep documentation or listings of the subprocedures for reference. When you are satisfied with the results, move these subprocedures to a common library so you won't have to keep copies of them in every library that use them.

It's easy to see how subprocedures can improve your programming efforts. Here are some examples:

1. Check for the existence of files and libraries.

2. Standardize file transfer to a remote system.

3. Rename a library.

4. A standard error screen display routine that uses the SCREEN subroutine to print the screen, thus recording the error.

5. Accept the name of a REPORT definition and the associated data files, then run REPORT with customized printer defaults.

6. Submit other procedures to the procedure queue (background) at specified times.

Let's see what you can do Please send listings of any particularly creative subprocedures you come up with for a possible feature in a future column. Next month we'll cover a few of the several procedure code generators found on the VS. See you then!


Figure 1: The TRACER2 Procedure


     PROCEDURE TRACER2

**********************************************************************
*
*                  TRACER2 - run-time procedure monitor
*
*    This procedure is a modified version of TRACER, which was featured
*    in the January 1987 ACCESS 87.  It accepts the name of a pro-
*    cedure, then runs it with the TRACE option.
*
*    The user is prompted for the file name.  After entry and a
*    check for file existance, the PROC program is run with the
*    test procedure passed to it.  The TRACE options screen is dis-
*    played, allowed specialized use of the trace options.  An option
*    to run DISPRINT in included for the convenience of the user.
*
*    For further discussion of the Procedure TRACE option, see Wang's
*    Procedure Language Reference, publication 800-1205-05.
*
*    SPECIAL NOTE: works ONLY for Procedure files; OBJECT PROGRAMS
*    WILL BOMB!  (See TRACERX, included with this diskette, for
*    an approach that will work with object files.)
*
*    Written by Dennis S. Barnes
*
*    MODIFICATION HISTORY
*
*    Version 1.0   10/25/86   Initial version.
*    Version 1.01 - revised to use $VERIFY to check enter file name
*
**********************************************************************

*    &MESSAGE Declared GLOBAL to receive message data from $VERIFY
     DECLARE &MESSAGE              GLOBAL STRING (71)

     DECLARE &INFIL, &INLIB        STRING (08)
     DECLARE &INVOL                STRING (06)

     DECLARE &RUNSTEP              STRING (03) INITIAL "@  "
     DECLARE &ALARM                STRING (03)
     DECLARE &RC                   INTEGER
     DECLARE &BLINKFAC, &BRITEFAC  STRING (01)

*    Field Attribute Characters (FAC's) follow
     ASSIGN &BRITEFAC    = &BYTE(132)    [ Equivalent to 84 HEX ]
     ASSIGN &BLINKFAC    = &BYTE(148)    [     "      "  94  "  ]

     ASSIGN &MESSAGE     = &BRITEFAC !!
                         "Please enter parameters and press (RETURN)"

S00: ASSIGN &INFIL       = " "     [ Initialize input file name ]
     ASSIGN &ALARM       = "NO "

S01: PROMPT              PFKEY     = &RUNSTEP (2,2),
                         ALARM     = &ALARM
     CENTER BRIGHT LINE  "Procedure Run & trace facility";;
     CENTER "Enter the name of the procedure to be traced:";;
     CENTER              "FILE    =", UPPER &INFIL;
     CENTER              "LIBRARY =", UPPER &INLIB;
     CENTER              "VOLUME  =", UPPER &INVOL, " ";;
     CENTER              "Press PF(14) to display print files";
     CENTER              "Press PF(16) to exit               ";;
     CENTER              &MESSAGE(1,*)

     IF &LABEL(&RUNSTEP) GOTO &RUNSTEP
     ASSIGN &ALARM       = "YES"
     ASSIGN &MESSAGE     = &BLINKFAC !!
     "Invalid key pressed - please try again"
     GOTO S01

@0:  RUN $VERIFY [ in library on volume ]
     USING               &INFIL, &INLIB, &INVOL

     IF &MESSAGE = " "   GOTO S02
     ASSIGN &ALARM       = "YES"
     GOTO S01

S02: IF EXISTS FILE &INFIL IN &INLIB ON &INVOL         GOTO S03
     ASSIGN &MESSAGE     =  "File does not exist - please re-enter"
     ASSIGN &ALARM       = "YES"
     GOTO S01

S03: ASSIGN &MESSAGE     = &BRITEFAC !!
                         &INFIL !! " successfully completed"

S04: RUN PROC IN @SYSTEM@ [ on volume ]
     ERROR EXIT          IS S05
     CANCEL EXIT         IS S05
     ENTER OPTIONS       [ pfkey ] 09,       FILE      = &INFIL,
                         LIBRARY   = &INLIB, VOLUME    = &INVOL
     DISPLAY TRACE       RUNONLY   = YES,    RESOURCE  = YES
     ENTER OPTIONS       16

S05: ASSIGN &RC          = S04
     IF &RC = 0          GOTO S00

     ASSIGN &ALARM       = "YES"
     ASSIGN &MESSAGE     = &BLINKFAC !! &INFIL !!
                         " ended with return code " !! &RC
     GOTO S01

@14: RUN DISPRINT IN USERAIDS [ on volume ]
     ASSIGN &ALARM       = "NO "
     ASSIGN &MESSAGE     = &BLINKFAC !!
                         "DISPRINT completed"
     GOTO S01

@16: RETURN

  [ Prior Article ]     [ Return to the Catalog of articles ]     [ Next Article ]  


Copyright © 1987 Dennis S. Barnes
Reprints of this article are permitted without notification if the source of the information is clearly identified