Exercise 6. Read SYSTEM SEGID

The assignment

Write a procedure that lists the logical shared segments (LSEGMENT) that are part of the physical shared segment (PSEGMENT) (for example CMSFILES).  The procedure should also display the size in bytes for each logical segment, and calculate the remaining free space in the physical segment.

The information can be found in file SYSTEM SEGID S2.  The records that you have to extract look like these:

   PSEGMENT  CMSFILES  01C00000  00190000  02/17/94  13:42:33
   LSEGMENT  xxxxxx    01C00000  000C64E8
   LSEGMENT  yyyyyy    01CC6528  000C31B0

The fourth column indicates the sizes in hexadecimal notation.  So the remaining free space is the size of the PSEGMENT minus the sum of the LSEGMENT members.  Your output should resemble to this:

   Physical segment CMSFILES contains following logical segments :
      DMSDAC   size 812264 bytes
      DMSSAC   size 799152 bytes
   Space remaining in physical segment = 26984 bytes

General comments.

Conversion routines

The main difficulty here is to find the correct conversion routines in REXX (C2D, X2D, X2C...).  It's always difficult to remember which one to use.  In order to help you with this problem, the goodies contains yet another tool, namely XTOX.  You call it with whatever argument, and it returns all possible results from the different functions.  For example: XTOX 2D4F returns

   C2D(2D4F)=impossible
   C2X(2D4F)=F2C4F4C6                      =X'C6F2C3F4C6F4C3F6'
   D2C(2D4F)=impossible
   D2X(2D4F)=impossible
   X2C(2D4F)=–!                            =X'2D4F'
   X2D(2D4F)=11599                         =X'F1F1F5F9F9'

Reuse variables

It is common to see programs where too many variables are created, while it would be possible to reuse the variables.  Instead of coding

   parse var rec . . . . segsize . 
   size=x2d(segsize)

it's better to code

   parse var rec . . . . segsize . 
   segsize=x2d(segsize)

We agree, this procedure doesn't use many different variables, but it should become a reflex to avoid creation of extra REXX variables when not really required.  REXX has the advantage to other programming languages that you don't have to declare variables, but this easily leads to a waste of storage, and on personal systems, storage may still be constrained for some users.

Best technique

You will see, once again, that the solutions using CMS Pipelines are the shortest, easiest to read (if you understand PIPEs), and best performing.  Remember you can take a Telecourse on CMS Pipelines on this site too.

Locating strings

Many read the whole file and then analyze the records in REXX to find the proper segment cards.  You should remember to use the FIND or LOCATE options of the different I/O tools (see lesson 4 for more details on these). 

A typical solution

   ! /**********************************************************************/
   ! /* QLSEG - Created by RUDI                                            */
   ! /* Function : list free space in physical segments                    */
   ! /* Parameters : physical segment name                                 */
   ! /**********************************************************************/
 1 ! Address Command
 2 ! parse upper source . . myname .
 3 ! parse upper arg pseg
   !                                 /* inform user about parameter option */
 4 ! if pseg='' then say 'you can use ',
 5 ! myname' with a PSEGMENT name as parameter'
 6 ! freespace=0
   !                      /* get lines from system segid s into vars lin.x */
 7 ! 'EXECIO * DISKR SYSTEM SEGID S (FINIS STEM LIN.'
 8 ! if RC<>0 then call Error_Exit RC,'cannot read SYSTEM SEGID S file'
 9 ! do i=1 to lin.0 by 1                            /* process lines      */
10 !    parse var lin.i segtype segname segstart seglen .
11 !    if segtype='PSEGMENT' then do                /* lets get Physical  */
   !                   /* new pseg so tell the remaining space of previous */
12 !       if freespace<>0 & found=1 then say 'Space remaining in',
13 !        'physical &gml. 'freespace' bytes'
14 !       if pseg='' ! pseg=segname ! pseg='ALL' then do
15 !          found=1; remember_found=1
16 !          say 'the Physical segment 'segname,
17 !          ' has following logical segments'
18 !          segmlenght=x2d(seglen)
19 !       end
20 !       else found=0
21 !    end
22 !    if segtype='LSEGMENT' & found=1 then do      /* it becomes logical */
23 !       say '     'segname 'size 'x2d(seglen)' bytes'
24 !       freespace=segmlenght-x2d(seglen)
25 !       if i=lin.0 then say 'Space remaining in physical &gml. ',
26 !       freespace' bytes'
27 !    end
28 ! end
29 ! if remember_found<>1 then call Error_Exit 28,'No Physical segment 'pseg
30 ! call Error_Exit 00,'All done'
   ! /****************** Exit routine ********************************/
31 ! Error_Exit&gml.     /* same as our standard */

This solution allows the user to specify a single segment name or the keyword ALL.  In the latter case, all segments are listed.  The student however forgot to mention this feature in the help section.

  1. Variables could have been reused better.
  2. Lines 4-5. Nice feedback to the user, but an exit from the procedure is missing, so that invalid parameters are used.
  3. Lines 5,13,17 and 26. These are continuation lines.  As the continuation lines are not indented, it is less easy to follow the logic.
  4. Line 9. by 1 is the default anyway.
  5. Line 10. segstart is an unused variable.

This is a very nice and complete procedure, bravo.

   ! /* QLSEG exec */
 1 ! Arg segid . /* no detection of not existing seg-names */
 2 ! If segid="" Then segid="CMSFILES"
 3 ! Say "Physical segment "segid" contains following logical segments:"
 4 ! Address command "PIPE < system segid s",
   !    "! frlab PSEGMENT  "segid,
   !    "! var segn",
   !    "! drop 1",
   !    "! tolab PSEGMENT",
   !    "! specs /   / 1 w2 n /size/ nw w4 x2d nw /bytes/ nw",
   !    "! cons",
   !    "! specs w3 1",
   !    "! join * /+/",
   !    "! var sum"
 5 ! Interpret "sum="sum
 6 ! Parse var segn . . . seglen .
 7 ! Say "Space remaining in physical segment = "x2d(seglen)-sum" bytes"
 8 ! Return

This student anticipated our comment that there is no error handling (missing segment name parameter for example).

For those of you that have no CMS Pipelines experience, a bit more detail of what this PIPE does:

< system segid sreads the file
frlabsearches until a record begins with label PSEGMENT CMSFILES.
var segnputs that record (if found) in REXX variable segn
drop 1and drops it from the pipe as it is no longer needed
tolabtakes records until another PSEGMENT card is found
specsmanipulates the records so that
  1. 2 blanks are prefixed (/  / 1)
  2. second word is concatenated next (word2 next)
  3. the string "size" is written as next word (/size/ nextword)
  4. 4th word comes next, after conversion to decimal (word4 x2d nextword)
  5. and finally comes string "bytes" (/bytes/ nextword)
consthe so reformatted records are written to the screen.
specs w3 1third word of each record is extracted (put in column 1)
join * /+/all (*) records are joined to each other with an intervening + sign
var sumand result is put in variable sum.

So, the result of this PIPE is:

  1. variable segn contains the PSEGMENT card.
  2. all logical segments are listed to the console screen
  3. variable sum contains a string looking like this:
        segment_size1+segment_size2+segment_size3+...
    

The variable sum is used in the interpret "sum="sum statement at line 5.