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
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'
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.
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.
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).
! /**********************************************************************/ ! /* 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.
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 s | reads the file |
frlab | searches until a record begins with label PSEGMENT CMSFILES. |
var segn | puts that record (if found) in REXX variable segn |
drop 1 | and drops it from the pipe as it is no longer needed |
tolab | takes records until another PSEGMENT card is found |
specs | manipulates the records so that
|
cons | the so reformatted records are written to the screen. |
specs w3 1 | third word of each record is extracted (put in column 1) |
join * /+/ | all (*) records are joined to each other with an intervening + sign |
var sum | and result is put in variable sum. |
So, the result of this PIPE is:
segment_size1+segment_size2+segment_size3+...
The variable sum is used in the interpret "sum="sum statement at line 5.