REXX: Find a String In a PDS

One of the first utilities I wrote using REXX in a MVS TSO environment was a simple program to search a named PDS (partitioned data set) for a specified string. The program accepts two inputs: the name of the PDS to be searched and the string to search for. It then writes the search results to an output file for subsequent browsing.

Following is a sample session that illustrates the program in operation. Table 1 shows the screen dialog that goes on between the user and the program. Note that in this session I have "forgotten" to provide the command line paramters. Bold face text are my inputs to the program.

Table 1. Screen Session Input and Output

===> ex showstr2

Error: You did not specify a dataset
------------------------------------
Enter name of PDS to search:
p.sas

Error: You did not specify a string.
------------------------------------
Enter the string to find:
compress(
member=myuserid.P.SAS($AATEST)
member=myuserid.P.SAS($ADOCLOC)
member=myuserid.P.SAS($ALLOC)
member=myuserid.P.SAS(WS9605X)
member=myuserid.P.SAS(X#MERGE3)
member=myuserid.P.SAS(XMIT)
member=myuserid.P.SAS(XMIT2)
member=myuserid.P.SAS(XPROC)
member=myuserid.P.SAS(ZERO)
*** SEARCH COMPLETE ***

In this version of the program, the output file name is hard coded. Let's take a look at Table 2 which is a listing of the output file's contents following the search.

Table 2. Report File Output

------------------------------------------------
---  Searching  P.SAS  for string < COMPRESS( >
------------------------------------------------
------------------------------------------------
---->  $EXAMPLE  has the string < COMPRESS( >
VARIABLE=COMPRESS(VARIABLE,'CHARS_TO_REMOVE');
VARIABLE=COMPRESS(VARIABLE,'CHARS_TO_REMOVE');
VARIABLE=COMPRESS(VARIABLE); /* THIS REMOVES ALL BLANKS */
   DO; MB_PRNT=COMPRESS((MB_NAME || SUBSTR(AVALU,NDX,1)));
------------------------------------------------
---->  #PUT  has the string < COMPRESS( >
COLNUMS=COMPRESS(FORM,'$ACDHMOPRYZ');
COLNUMS=COMPRESS(FORM,'$ACDHMOPRYZ');
------------------------------------------------
---->  #SAMPLES  has the string < COMPRESS( >
      MB_PRNT=COMPRESS((MB_NAME || SUBSTR(AVALU,NDX,1)));
      MB_PRNT=COMPRESS((MB_NAME || SUBSTR(AVALU,NDX,1)));
------------------------------------------------
---->  CODETEMP  has the string < COMPRESS( >
XMSG=COMPRESS(XMSG) || 'CABS';
XMSG=COMPRESS(XMSG) || 'CABS';
XMSG=COMPRESS(XMSG) || ',NICD';
XMSG=COMPRESS(XMSG) || '>';
------------------------------------------------
---->  MAKCSV  has the string < COMPRESS( >
SID=COMPRESS(SID);
SID=COMPRESS(SID);
------------------------------------------------
---->  VERIFY  has the string < COMPRESS( >
ID=COMPRESS(ID);
ID=COMPRESS(ID);
------------------------------------------------
-------------- END OF SEARCH  ------------------
------------------------------------------------

As you can see, the program identifies the PDS member that the string was found in and prints out the line in which the string was found.

Now that you've previewed a sample session and the program's report output, here is the REXX program source code. Use this code to further your understanding of how REXX works in an MVS TSO environment. Be forewarned that you use this code at your own risk and I make no guarantees that it will work on your system.

Complete REXX Program Source Code

001 /**                               REXX                             **/
002 /** NAME: SHOWSTR2                                                 **/
003 /** TASK: test writing results to a file                           **/
004 /** PARM: STRING TO FIND                                           **/
005 /** CMD:  STR2FND pdstosearch stringtofind                         **/
006 /**                                                                **/
007 /**----------------------------------------------------------------**/
008 /**step00: Move command line parameters into variables             **/
009 arg pdsname str2fnd
010 /**----------------------------------------------------------------**/
011 /**step01: Test for parameters                                     **/
012 /**----------------------------------------------------------------**/
013 if pdsname = "" then
014    do
015       say "Error: You did not specify a dataset"
016       say "------------------------------------"
017       say 'Enter name of PDS to search:'
018       pull pdsname
019    end
020 if str2fnd = "" then
021    do
022       say "Error: You did not specify a string."
023       say "------------------------------------"
024       say 'Enter the string to find:'
025       pull str2fnd
026    end
027 /**----------------------------------------------------------------**/
028 /**step02: Test for PDS existence                                  **/
029 /**----------------------------------------------------------------**/
030 if sysdsn(pdsname) <> "OK" then
031    do
032       say "Error: Specified PDS not found:" pdsname
033       say "Error: " pdsname " > " sysdsn(pdsname)
034       say "Press Enter to continue"
035       pull uresp
036       exit 8
037    end
038 /**----------------------------------------------------------------**/
039 /**step03: Invoke OUTTRAP to capture the LISTD program output      **/
040 /**        NOTE: this works because LISTD uses PUTLINE for output  **/
041 /**----------------------------------------------------------------**/
042 call outtrap "mbrs."
043 /**----------------------------------------------------------------**/
044 /**step04: Call the LISTD program to get the member list           **/
045 /**----------------------------------------------------------------**/
046 "LISTD" pdsname "MEMBERS"
047 /**----------------------------------------------------------------**/
048 /**step05: Turn off outtrap                                        **/
049 /**----------------------------------------------------------------**/
050 call outtrap "off"
051 /**----------------------------------------------------------------**/
052 /**step06: identify point at which the member list starts          **/
053 /**        this will be the value in ndx                           **/
054 /** say 'test - there are ' mbrs.0 '  members'                     **/
055 /**----------------------------------------------------------------**/
056 do ndx=1 to mbrs.0
057    if mbrs.ndx = "--MEMBERS--" then leave
058 end
059 ndx=ndx+1
060 /**-----------------------------------------------------------------**/
061 /**step04: open the file to write the output to                     **/
062 /**-----------------------------------------------------------------**/
063 "ALLOC FI(XXOUT) DA('JPLAXCO.PRINT') MOD REUSE"
064 IF RC \= 0 THEN
065    DO
066      SAY '*** ERROR - LOG ALLOCATION FAILED: ABENDING'
067      EXIT 0
068    END
069 /**-----------------------------------------------------------------**/
070 /**step07: Convert the pdsname to make sure it is fully qualified   **/
071 /**        This adds the high level qualifier, if needed            **/
072 /**-----------------------------------------------------------------**/
073 call listdsi pdsname
074 fullname=sysdsname
075 /**-----------------------------------------------------------------**/
076 /**step07: Search each member for the string                        **/
077 /**        parse copies the data in mbrs.x into the memname variable**/
078 /**        strip removes leading and trailing blanks                **/
079 /**        EXECIO is the REXX funtion to read+write files           **/
080 /**               * means process all records in the file           **/
081 /**               DISKR specifies Read                              **/
082 /**               XXIN  is the DDname to read from                  **/
083 /**               ( says additional parms follow                    **/
084 /**               FINIS says to close the DD when finished          **/
085 /**               STEM  says to read the records into a stem var.   **/
086 /**               IN.  is the name of the stem variable             **/
087 /**-----------------------------------------------------------------**/
088 lot.1="------------------------------------------------"
089 lot.2="---  Searching " pdsname " for string <" str2fnd ">"
090 lot.3="------------------------------------------------"
091 lot.0=3
092 "EXECIO" lot.0 "DISKW XXOUT (STEM lot."
093 do curmbr = ndx to mbrs.0
094    parse value mbrs.curmbr with memname
095    memname=strip(memname)
096    hdr=1
097    say "member="fullname"("memname")"
098    "ALLOC F(XXIN) DS('"fullname"("memname")') SHR REUSE"
099    "EXECIO * DISKR XXIN (FINIS STEM in."
100    "FREE F(XXIN)"
101    fnd=0
102    do recid=1 to in.0
103       if pos(str2fnd,in.recid) > 0 then
104         do
105            if hdr = 1 then
106              do
107               lot.1="------------------------------------------------"
108               lot.2="----> " memname " has the string <" str2fnd ">"
109               lot.3 = in.recid
110               lot.0=3
111               "EXECIO" lot.0 "DISKW XXOUT (STEM lot."
112               hdr=0
113              end
114            lot.1 = in.recid
115            lot.0=1
116            "EXECIO" lot.0 "DISKW XXOUT (STEM lot."
117         end
118    end
119 end
120 say '*** SEARCH COMPLETE ***'
121 lot.1="------------------------------------------------"
122 lot.2="-------------- END OF SEARCH  ------------------"
123 lot.3="------------------------------------------------"
124 lot.0=3
125 "EXECIO" lot.0 "DISKW XXOUT (STEM lot."
126 "EXECIO 0 DISKW XXOUT (FINIS"
127 "FREE F(XXOUT)"
128 exit 0

Return to the Mainframe section index.