Reading IFS Directories in Cobol – Recursively!

Article ID: 54562

In "Reading IFS Directories in Cobol," (April 19, 2007, article ID 54504 ), I demonstrated how to use a series of Unix-type APIs from a Cobol program to read IFS directories. The program's user interface showed all the stream files of one particular IFS directory, but omitted all subdirectory entries. The program was not able to deal with tree structures in an easy, natural way. Recursion seems to be the natural solution to this problem because, in the words of Niklaus Wirth, "Recursive algorithms are particularly appropriate when the underlying problem or the data to be treated are defined in recursive terms." In this article, I present a recursive version of last week's program that demonstrates how to walk through an IFS directory tree.

In business programming we rarely have to deal with recursion. If fact, I haven't worked with recursion since the old good days when I was a computer science student. However, there is no reason to avoid recursion if, as professor Wirth says, the data itself is defined in recursive terms, as is the case with tree structures. A program is recursive if it contains an explicit or implicit reference to itself.

The following example from ILE Cobol Programmer's Guide (SC09-2540-05) illustrates how to write a recursive program in Cobol:

ID DIVISION.
PROGRAM-ID.  FACTORIAL RECURSIVE.

ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
	SOURCE-COMPUTER.  IBM-ISERIES.
	OBJECT-COMPUTER.  IBM-ISERIES.

DATA DIVISION.
WORKING-STORAGE SECTION.
01	numb		PIC 9(4) VALUE 5.
01	fact		PIC 9(8) VALUE 0.

LOCAL-STORAGE SECTION.
01	num		PIC 9(4).

PROCEDURE DIVISION.
	MOVE numb TO num.
	IF numb = 0
		MOVE 1 TO FACT
	ELSE
		SUBTRACT 1 FROM numb
		CALL "FACTORIAL"
		MULTIPLY num BY fact
	END-IF.
	DISPLAY num "! = " fact.
	GOBACK.

Here are a few notes on the preceding code sample:

  1. The RECURSIVE clause in the IDENTIFICATION DIVISION provides support for recursion in Cobol.
  2. The LOCAL-STORAGE section associates a set of local objects (i.e., a set of variables and constants which are defined locally to the program). Each time such a program is activated recursively; a new set of local variables is created and initialized.
  3. The WORKING-STORAGE section associates a set of global variables, shared by all instances of the program.
  4. You should make sure that the ultimate depth of the recursion is not only finite, but quite small. The LOCAL-STORAGE section has a higher overhead per call because it must be initialized in each call, and requires additional system resources per program instance.
  5. The GOBACK Cobol statement is particularly important in this context. If the program encounters the classic STOP RUN statement instead of GOBACK, all the program instances in the call stack are terminated.

Traversing the Directory Tree

Because this program is an adaptation of the one in the previous article, I only explain the changes I made, and don't repeat what I said in the previous article. The major change is the removal of the user interface logic: A separate program now manages the entire user interface. As a direct consequence of this change, the program gained readability and elegance.

The WORKING-STORAGE section includes all the variables whose value shouldn't be reinitialized in each program instance, but instead, should keep the same value across all instances. The rest of the variables were included in the LOCAL-STORAGE SECTION. A special first-instance flag was added to the WORKING-STORAGE SECTION, so that some routines are executed only in the first recursion instance.

01 switches-area.
    03 first-instance-flag PIC 1 VALUE B"0".
       88 is-first-instance      VALUE B"0".
       88 next-instances         VALUE B"1".

IF is-first-instance
   CALL PROCEDURE "CEEUTCO"
        USING BY VALUE ADDRESS OF offset_hours
              BY VALUE ADDRESS OF offset_minutes
              BY VALUE ADDRESS OF offset_seconds
              OMITTED
   END-CALL
   MOVE "/" TO root-directory-name
   MOVE "/transfer" TO default-directory-name
   PERFORM create-dtaq
   PERFORM clear-dtaq
   PERFORM go-root-directory
   SET next-instances TO TRUE
END-IF. 
PERFORM go-default-directory

On my system, "transfer" is the name of the first directory I wish to "visit". If, in the course of this visit, I encounter a subdirectory, I'll re-initialize the default-directory-name variable with the name of the subdirectory and call a new instance of the program.

EVALUATE st_objtype
   WHEN "*STMF"
       PERFORM write-dtaq
   WHEN "*DIR"
       IF d_name (1:d_namelen) NOT = "."   AND
           d_name (1:d_namelen) NOT = ".."
            PERFORM build-default-directory-name
            CALL "RECURDIR"
       END-IF
   WHEN OTHER
       CONTINUE
END-EVALUATE

In this new instance, the first-instance-flag variable will have a value of "1", so the program will skip directly to the code that processes the subdirectory.

Please note, there are two special directories that I don't wish to visit: "."(single dot) and ".." (two dots). These two special directory entries indicate the current and the parent directory, respectively.

The number of program instances in the call stack depends on the number of subdirectories below the first directory visited. On my system, the program encountered a subdirectory called "infoviewer," and under this, one called "monthly." The new program that manages the user interface displayed the following on screen:

It's worth noting that the full path name of each stream file is loaded in a hidden field of the subfile. This is necessary because the directory and stream file names shown on the screen might be truncated if they are too long.

And that’s all! As with the program presented in my previous article, the directory information in this program is written in a keyed data queue. Also in this new version, a second program reads the data queue entries and builds a very simple "Work with" type user interface. Both programs are called from a CL program to ensure that they run in the correct sequence.

You can download the sample code for this article from the following link:
http://www.pentontech.com/IBMContent/Documents/article/54562_196_RecurseDirCobol.zip

More Information

More information about recursion in Cobol can be found in ILE Cobol Programmer’s Guide Version 5 (SC09-2540-05). You can read the PDF version of this book in the following link:
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/books/sc092540.pdf

In particular, check out the section titled "Using Recursive Calls" in Chapter 9, "Calling and Sharing Data Between ILE Cobol Programs".

You can find an RPG program example written by Scott Klement that reads directories recursively at:
http://www.systeminetwork.com/article.cfm?id=20235

ProVIP Sponsors

ProVIP Sponsors