How to determine a Natural module’s caller

I wanted to find out, from which module another Natural module was called. My goal was to make sure, that the module can only be called from a certain other module and raises an error, if a “disallowed” module calls it. I don’t want to get into the details here of why this is a bad idea in the first place 😉

In Ruby, this is a one liner (see Any way to determine which object called a method?):

caller.first

As it turns out, in Natural it’s not that simple. However, it’s not that hard, either. Thanks to a forum post (see Previous Program System Variable) I was able to quickly implement a short subroutine that does the job. It uses User Exit USR0600N (Get program level information) and looks like this:

DEFINE DATA
*
PARAMETER
01 P-CALLER (A8)
*
LOCAL
01 #NAMES (A8/1:32)
01 #LEVEL (P3/1:32)
*
01 #I (I4)
01 #STACK-SIZE (I4)
01 #INDEX-CALLER (I4)
*
END-DEFINE
*
DEFINE SUBROUTINE GET-CALLER
*
RESET P-CALLER
*
CALLNAT 'USR0600N' #NAMES(*) #LEVEL(*)
*
FOR #I 1 *OCC(#NAMES)
  IF #NAMES(#I) NE ' '
    #STACK-SIZE := #I
  END-IF
END-FOR
*
#INDEX-CALLER := 3
IF #STACK-SIZE GE 3
  P-CALLER := #NAMES(#INDEX-CALLER)
END-IF
*
END-SUBROUTINE
*
END

It can be called like this:

PERFORM GET-CALLER #CALLER

USR0600N returns the Natural modules currently on the stack in descending order (as you would expect from a stack). So if STACK calls STACK2 and STACK2 calls STACK3 and STACK3 calls GET-CALLER, USR0600N returns:

GET-CALLER (index 1; in fact, this would be the module's name, e.g. "GETCALL")
STACK3 (index 2)
STACK2 (index 3)
STACK (index 4)

This should explain the logic in GET-CALLER above. For the call chain above, WRITE *PROGRAM 'was called by <' #CALLER '>' results in:

STACK3 was called by <SMSTACK2>
STACK2 was called by <SMSTACK >
STACK  was called by <        >

Leave a Comment

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax