Monday, September 26, 2011

CICS: Scrolling logic for a KSDS file

This article explains how to implement a scrolling logic for KSDS (VSAM) file. Though this article looks pretty lengthy, if you remove the comments from the logic, it will look much simpler.

Assumptions :-
There is a menu program which accepts the full or partial key thru a screen and the program validates that the key is valid and there exists at least one record in the file for the key entered. The key is passed to the program which handles the scroll logic. The number records to be displayed in the screen is 20. The screen supports only PF4, PF5, PF7 and PF8 keys. As usual PF7, PF8 keys provides scroll backward, forward mechanisms respectively. PF4 key displays first 20 matching records and PF5 displays last 20 matching records.


Implemention


01 This-programs-commarea.
   05 Control-tracking-indicator Pic X(04).
   05 Key-passed Pic X(10).
   05 Last-key PIC X(10).
   05 First-key PIC X(10).

/* populate the commarea to the working storage field */

Move Dfhcommarea to This-prgrams-commarea

/* To find out the length of the key passed, we need to count the number of spaces present at the end of the key and subtract it from the maximum size of the key. The below code does this calculation*/

Move zeros to Ws-count
Inspect function reverse(key-passed) tallying Ws-count for all leading spaces.
Ws-passed-key-length = Length of key-passed - Ws-count

/* when control comes from the menu program, the value of the control tracking indicator will be MENU, so the program can execute the logic for first time process */

If control-tracking-indicator = 'MENU'
   Perform First-time-para
Else
   Perform Subsequent-process-para
End-if

/* Send-data-only-with-no-erase is set when user is already in the first/last page and the user pressed PF7 or PPF8 key */

If Send-data-only-with-no-erase is set
   Send map with data only and no erase option
Else
   Send map with erase option
End-if

/* pass the This-programs-commarea to the Dfhcommarea, so the program can keep track of its data */

Return control to CICS with This-programs-commarea

First-time-para

/* change the value of the indicator, so the program can execute the subsequent
process para when control enters next time*/

Move "CURP" to Control-tracking-indicator

/* we need to apply scroll forward logic during the first time process. Last-key is the starting point for the scroll forward logic. So, populate the passed key to the Last-key */

Move Key-passed to Last-key

/* key length is calculated at the beginning of the program. Fill remaining positions of the key with low-values, so we can position the record pointer just prior to the first matching record */

Move Low-values to Last-key((Ws-passed-key-length+1):)

/* set Sw-PF8-key-pressed as we are going to apply scroll forward logic for first time processing */

Set Sw-PF8-key-pressed to true
Perform Main-process
Perform Populate-data-to-screen

Subsequent-process-para

Set valid-key-pressed to true

Evaluate EIBAID
  When PF4

/* We need to apply the scroll forward logic (PF8 logic) when PF4 key is pressed. Last-key is the starting point for the scroll forward logic. key length is calculated at the beginning of the program. Fill remaining positions of the key with low-values, so we can position the record pointer just prior to the first matching record. Populate appropriate message to the message field to communicate to the user that this is the first screen */

    Set Sw-PF4-key-pressed to true
    Move Key-passed to Last-key
    Move Low-values to Last-key((Ws-passed-key-length+1):)
    Move 'Top of the data reached” to message field
  When PF5

/* We need to apply the scroll backward logic (PF7 logic) when PF5 key is pressed. First-key is the starting point for the scroll backward logic. key length is calculated at the beginning of the program. Fill remaining positions of the key with high-values, so we can position the record pointer right next to the last matching record. Populate appropriate message to the message field to communicate to the user that this is the Last screen */

    Set Sw-PF5-key-pressed to true
    Move Key-passed to First-key
    Move High-values to First-key((Ws-passed-key-length+1):)
    Move 'Bottom of the data reached” to message field
  When PF7
    Set Sw-PF7-key-pressed to true
  When PF8
    Set Sw-PF8-key-pressed to true
  When other

/* when any other key is pressed, we need to communicate to the user with appropriate message. Switch Send-data-only-with-no-erase is set to not to erase the current screen, as we are supposed send the same screen with a message to inform that the user has pressed invalid key */


    Set Sw-invalid-key to true
    Populate error message to the message field
    Set Send-data-only-with-no-erase to true
End-evaluate

Move zeros to Number-of-records-processed

/* execute main-process only when valid-key-pressed is pressed */

If valid-key-pressed
   Perform Main-process

/* during PF7 processing it is possible that there are less than 20 records to display. In this situation set Sw-PF4-key-pressed to true to invoke the PF4 key processing, so, we can display first 20 matching record of the key passed and set appropriate message to inform that the user has reached the first page */

   If Number-of-records-processed > 0 and < 20 and Sw-PF7-key-pressed
      Move 'Top of the data reached” to message field
      Set Sw-PF4-key-pressed to true
      Perform Main-process
   End-if

/* During PF7 processing, it is possible that the current screen is already displaying the first matching record of the key passed.
During PF8 processing, it is possible that the current screen is already displaying the last matching record of the key passed.
In these situations Number-of-records-processed will be zeros and we will be displaying appropriate message to the user that first/page last page was reached without erasing the current detail lines in the screen. So, the below “IF” condition was introduced to not to execute the Populate-data-to-screen para in this situation */

   If Number-of-records-processed > 0
      Perform Populate-data-to-screen
   End-if
End-if

Main-process

/*
For PF7 processing, we always need to use the First record key of the current screen as the starting point.

For PF5 processing, before control comes to this para, the First-key will be populated with the Key-passed and if the key-passed is a partial key, the remaining positions will be populated with high-values so we can position the record pointer right next to the last matching record.

The Else part of the below IF condition takes care of PF8 and PF4 logic.

For PF8 processing, we always need to use the Last record key of the current screen as the starting point.

For PF4 processing, before control comes to this para, the Last-key will be populated with the Key-passed and if the key-passed is a partial key, the remaining positions will be populated with low-values so we can position the record pointer right prior to the first matching record.

*/

If Sw-PF5-key-pressed or Sw-PF7-key-pressed
   Move First-key to File-key
Else
   Move Last-key to File-key
End-if

/* Issue STARTBR against the file using the File-key with Greater than or equal to option */

STARTBR the file using File-key

/* During PF5 processing, it is possible to get record not found condition during STARTBR. Assume that the key passed from the menu program is “5555” which is partial key and the last record in the file is “5555123456”. So, the File-key will be populate with “5555......”, where “.” (dot) represents the high-values. In this case, File-key is greater than the record key of the last record present in the file. So, this will generate NOTFOUND condition. To handle this situation, entire File-key is populated with high-values and when we do STARTBR with this key, the record pointer will be positioned right next to the last record of the file and the immediate READ PREV will fetch the last record */

If EIBRESP = NOTFND
   Move High-values to File-key
   STARTBR the file using File-key
   READ PREV file, set End-of-file-reached if EIBRESP = ENDFILE
End-if

/* Process-record-para issues READ PREV during its each iteration to read the file backwards for PF7 key processing. The below extra READ PREV is issued to skip the first record of the current screen */

If EIBAID = PF7
   READ PREV file, set End-of-file-reached if EIBRESP = ENDFILE
End-if

/* Process-record-para issues READ NEXT during its each iteration to read the file in forward direction for PF8 key processing. The below extra READ NEXT is issued to skip the last record of the current screen */

If EIBAID = PF8
   READ NEXT file, set End-of-file-reached if EIBRESP = ENDFILE
End-if

Move zeros to Number-of-records-processed

Perform Process-record-para until End-of-file-reached
                               or Number-of-records-processed = 20

/* During PF7 processing, it is possible that the current screen is already displaying the first matching record of the key passed. In this situation Process-record-para will set the End-of-file-reached switch and exits out its loop and we should send the current screen without erasing it and populate a message to the screen to communicate that the user is already at the first screen.
During PF8 processing, it is possible that the current screen is already displaying the last matching record of the key passed. In this situation Process-record-para will set the End-of-file-reached switch and exits out its loop and we should send the current screen without erasing it and populate a message to the screen to communicate that the user is already at the last screen.

Switch Send-data-only-with-no-erase is set to not to erase the current screen, as we are supposed send the same screen with a message to inform that the user is in first/last page.
*/
If End-of-file-reached and number-of-records-processed = 0
   If EIBAID = PF7
      Populate 'Top of the data reached' to the message field
   Else
      Populate 'Bottom of the data reached' to the message field
   End-if
   Set Send-data-only-with-no-erase to true
End-if

Process-record-para

/* For both PF5 and PF7 processing, we need to read the file backwards.
The ELSE part in the below IF condition handles the PF8 & PF4 processing. During PF8 & PF4 processing we need to read the file in forward direction. */

If Sw-PF5-key-pressed or Sw-PF7-key-pressed
   READ PREV file, set End-of-file-reached if EIBRESP = ENDFILE
Else
   READ NEXT file, set End-of-file-reached if EIBRESP = ENDFILE
End-if

/* It is possible to reach “end of file” situation during READ NEXT/PREV. Note that READ PREV also generates “end of file” condition when it tries read past the first record of the file. So, the below “If” condition is included to confirm the successful read*/

If read prev/next is successful

/* In the case of the partial key, Ws-passed-key-length will have the length of the partial key. If full key is passed, the Ws-passed-key-length will have maximum length of the key. The below IF condition is issued to make sure we are processing the records matching the passed key. */

   If Current-record-key (1:Ws-passed-key-length)
        = Key-passed (1:Ws-passed-key-length)

/* During PF5, PF7 processing, the program is reading the file in backward direction. So, we need to populate the First-key with the current-record-key, so this can be as the starting point for the PF7 processing, if PF7 key is pressed next time. The ELSE handles the PF4 & PF8 processing and it populates the current-record-key to the Last key, so this can be used as starting point for the PF8 processing, if PF8 key is pressed next time */

      If Sw-PF5-key-pressed or Sw-PF7-key-pressed
         Move Current-record-key to First-key
      Else
         Move Current-record-key to Last-key
      End-if

/* Keep tract how many matching records are retrieved */
      
      Add 1 to Number-of-records-processed

/* We need to store the record key of the first matching record. For PF5 and PF7 processing, we read the file in backward direction. So, the first record need to be stored to that Last-key, and this can be used as starting point if PF8 key is pressed next time.
The ELSE part handles the PF4 and PF8 processing. For PF4 and PF8 processing, we read the file in forward direction. So, the first record need to be stored to that First-key, and this can be used as starting point if PF7 key is pressed next time. */
      If Number-of-records-processed = 1
         If Sw-PF5-key-pressed or Sw-PF7-key-pressed
            Move Current-record-key to Last-key
         Else
            Move Current-record-key to First-key
         End-if
      End-if

/* Store the current record in a working storage table, so this can be used to populate the detail lines in the screen */

      Store the current-record to
           the working-storage table(number-of-records-processed)
   Else

/* If there is no more matching record for the key passed, then set End-of-file-reached switch*/

     Set End-of-file-reached to true
   End-if
End if

Populate-data-to-screen

Initialize all the 20 detail lines in the screen

/* During PF5 and PF7 processing, we read the file in backward direction. The retrieved records are stored in the working storage table from the first occurrence. So, the first record from the table need to be populated to the last detail line of the screen, 2nd record from the table need to be populated to the preceding detail line of the last detail line and so on. Thus for PF5 and PF7 processing, the records from the working storage table need to be populated to the screen in reverse order. The “ELSE” part in the below “IF” condition handles the PF4 and PF8 processing and we do not need reverse the order of the working storage table for this. */


If Sw-PF5-key-pressed or Sw-PF7-key-pressed
   Move number-of-records-processed to Ws-Init-pos
   Move -1 Ws-increment
Else
   Move 1 to Ws-Init-pos
   Move +1 Ws-increment
End-if

Move zeros to Ws-count
Perform varying WS-IX from Ws-Init-pos by Ws-increment
   until Ws-count = number-of-records-processed
   Add +1 to Ws-count
   Populate data from working-storage table (WS-IX)
         to detail line (Ws-count) of screen
End-perform

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.