Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How many parameters rec'd by subroutine 2

Status
Not open for further replies.

Lunker

Programmer
Dec 13, 2002
54
US
This is for mainframe OS/390 COBOL.
We have a subroutine (SUB1) that was initially written to receive one 132 byte parameter and print a line of output. Several hundred programs were using it.

With laser printing capable of printing more characters, this routine was changed to handle either 132 or 198 bytes. To do this they added a second parameter with the length value.

They did not want to change all existing mainframe programs to have two parameters so an assembler routine was written. It was named SUB1 and the origininal SUB1 was renamed to SUB2. The assembler routine can determine if a second parameter is being used. SUB1 always calls SUB2 with two parameters. If only one parameter is received by SUB1, it calls SUB2 with a second parameter value of 132. If two parameters are received by SUB1, it calls SUB2 with those two parameters.

I would like to get rid of the assembler program. How can I get a COBOL program to determine if it received a second parameter?

I have tried to use ADDRESS OF. I can check the ADDRESS OF the second parameter and if it is NULL, I only have one parameter. But once I make a call with two parameters, there seems to always be an address associated with parameter 2. This needs to work if I call with one parameter, then call with two, and then call with one.

I cannot change the subroutine to require two parameters because there are a couple hundred programs already using it with one parameter. I want this change to be transparent to any of the existing root programs.

Any ideas?
 
Here's how it worked the last time I looked:

On entry, R1 points to a list of addresses. Each address points to one parameter. The last address of the list has its high-order bit set (e.g. OI with X'80').

That begs the issue of how to get to that bit. I think the way is by using BY CONTENT on the PROCEDURE DIVISION USING:
Code:
LINKAGE SECTION.
01  LS-PARM1-ADDRESS PIC S9(9) BINARY.
01  LS-PARM1-POINTER REDEFINES LS-PARM1-ADDRESS POINTER.
01  LS-PARM2-ADDRESS PIC S9(9) BINARY.
01  LS-PARM1-POINTER REDEFINES LS-PARM2-ADDRESS POINTER.
01  LS-PARM1.
    05  ETC
01  LS-PARM2.
    05  ETC.
PROCEDURE DIVISION USING BY CONTENT LS-PARM1-ADDRESS
                         BY CONTENT LS-PARM2-ADDRESS.
0000-MAINLINE.
    SET ADDRESS OF LS-PARM1 TO LS-PARM1-POINTER
    IF LS-PARM1-ADDRESS POSITIVE
         SET ADDRESS OF LS-PARM2 TO LS-PARM2-POINTER
*        We have two parms! Set a switch or something for this
    END-IF
etc.
[\code]
Note that this code is completely untested off the top of my head, so . . . :-)
 
Lunker,
Its a good question and I am also searching for more information.

But one thing let me suggest u. The task can be done by using a single parameter also (In analogy with variable length files in cobol)

U can use first few bytes to pass the length of the string.
This u only need to do if the text-length is > 132. (i.e. when u need to pass the second parameter) U can set the first few bit like '198*#@' followed by the actual text to print. In your subrutine u can check first 6 bytes if they contain a 3 digit number followed by '*#@' then u can divert it to a laser.

In this case only those program whose output length > 132 (for which u r passing a second parameter) will only be affected.


I dont know how feasible this is for u. But I suppose it can work

Devesh
 
3gm:
I tried your suggestion. First thing I realized is BY CONTENT is only allowed on the CALL. Get a compile error using it on PROCEDURE DIVISION header. Only allowed BY REFERENCE or BY VALUE. BY VALUE is only supposed to be used if you use BY VALUE on the CALL.

I tried BY VALUE anyway. At first I thought it was working. I was getting zero in the second field and a value in the first. Then I realized the second value when passed was never positive. I tried to reference the first parameter after I set the address and got a S0C4. When I displayed the binary value for that first parm address it was a negative number. I don't know what it's getting but what I was doing wasn't proper according to the IBM manual.

It looked for a minute like it had promise. The concept you had is one I have been trying to figure out and just can't get it to work when I am not allowed to change anything in the root program.

Thanks anyway.
 
deveshjogal:
Your suggestion would be a slick way to handle it if only the other programmers had thought of that 6 years ago when they made the change. Unfortunately there are many root programs already passing two parameters so I can't go in and change all of those. I would have preferred incorporating both values in one parameter also.

Thanks anyway.
 
3gm:
I have to apologize. I screwed up when I was writing my test code. I made the two binary fields 2 bytes rather than 4. When I made them 4 I was getting addresses and they were correctly pointing to my initial root program values.

2 problems though.
1. I don't really like using the BY VALUE option when I'm not using it as documented. Someday they'll clean that up and my code won't work.

2. I still have a problem.... As with other things I've tried. Once I pass a second parameter, there is an address in that area. I am unable to get rid of it. I have tried setting the ADDRESS OF the second parm to NULL when I leave but I think since it is not my area of memory, it doesn't seem to do anything.

It's pretty close though.
 
3gm:
I'm really close now but a little worried about what I'm getting.

I was able to move zero to the second binary parameter. Since I'm using BY VALUE it is the subroutine's memory location so it can be changed. Now the next time I call with one parameter, the second has zero in it and the subroutine knows it only has one parm.

Here's the problem I don't understand. The 2 parameters I am passing are back to back 01 levels in the root. 8 bytes for the first and 25 bytes for the second. The second address when received should be 8 bytes beyond the first. I redefined those binary fields as PIC X(04) and displayed them to see what I was getting.

The first one is 14 A8 D0 40 in hex. That translates to a decimal value of 346607680.
The second one is 94 A8 D0 48 in hex. Since the leftmost bit is a '1' it is a negative number. The decimal equivalent is -1800875960. Notice how close those two hex addresses look - 8 bytes apart except for that first half byte. Funny thing is, I am able to use those address and get the values I passed.

I still think there is something a little strange about using BY VALUE in the subroutine when it wasn't used in the root.

What do you think?

 
Lunker -

I should have been more specific. You MUST NOT use BY VALUE in the root program. That's the whole point. Your calling programs don't need to be changed. We use BY VALUE as a kludge to be able to actually get at the address rather than at what the address points to, if you get my drift. BY VALUE causes one less level of address indirection than BY REFERENCE.

What you're seeing is exactly what you should see. If you strip off the leading bit, the addresses are exactly 8 bytes apart which is what you say is supposed to happen in this case.

I wouldn't worry about IBM changing the behaviour of BY VALUE. It HAS to work that way.

As for setting the second address to zero, you shouldn't have to do that. In fact, you are changing the CALLER's memory (probably an area in the TGT?, not the passed variable itself) when you set it to zero. If the caller only passes one argument, you're going to overlay something you shouldn't. It should only be necessary to check that the first address is positive (i.e. the high-order bit is off) to tell you have two addresses. Otherwise, you only have the one address that's valid. (You did see that I'm testing only the FIRST one for positive?)

Sounds to me like you're in pretty good shape. Yes, it's convoluted, but I don't know of another way to handle it natively in COBOL.

Glenn
 
Hi Lunker,

If I understand your problem well, you have several programs in one run-unit that are caling your subroutine. The old ones are using one parameter, the newer ones are using two. The called module can remember an old value of the address of the second parameter when at a later time an old type call takes place.

There are two possibilities to solve this:

1) The newer programs are passing something special in the first parm that indicates that this is the newer way to call. So they give a parm with a value like:
" magic number 7287388563462688001077656 this is the newer parm wit length of: ....."

so it will never happen that an old program is giving this parm. The second parm is ok when the first parm has this specific value.

2) An other, technical way to solve this is to set the adress of the second parm before the exit program on NULL.

I guess both methods will work for you.

Regards,

Crox
 
Hey Glenn,
I hadn't noticed that you were checking the first address for positive. I looked at my test and see now that it works the way you say. When I send 1 parameter, the first address is negative. When I send 2, the second address is negative. Why is it sending a negative address and how does it work when I set the address of a Linkage Section element to that negative address? I can see it is working but I don't know how it handles that negative situation.

The reason I was setting the second address to zero was because I was checking the second address to determine if I had one or two parameters.

I do understand that I don't want to use BY VALUE in the caller programs. I know that the default BY REFERENCE is passing addresses and by using BY VALUE in the subroutine you get the address. I had tried to do that in the past but never tried BY VALUE when IBM manual said it could only be used if the caller used BY VALUE.

If you could give me a little insight on the reason for that negative address, I will implement this change.

Thanks for all your help.

Doug
 
Doug -

By long-standing convention, the last address in a parameter list is marked by setting the high-order bit to 1. If you think back to your math/computer science courses where they talked about 2's complement arithmetic, you'll remember that negative numbers all have the high-order bit turned on. Hence, the last parameter address field is always a negative number (when evaluated as a signed binary integer) while all of the other parameter addresses in the list have a zero leading bit and are therefore postive.

It is important to note that the IBM mainframe uses 24 or 31 bit addressing so the high-order bit of a 4-byte field is ALWAYS ignored when it is used as an address.

Hope that helps you understand why it works the way it does.

Regards,

Glenn
 
Thanks Glenn:
That clears it up now. I could see that the negative address I was getting started with a 1001 making it negative. The explanation of the last parameter in the list being marked negative helps.

We're using 31-bit addressing and I never thought of it until you responded. The 32nd bit is the sign. If I ignore that, the addresses I was displaying were 8 bytes apart just like I expected.

I've been trying to come up with this solution for a long time. I was close, but your help is what made it work.

Thanks a lot.

Doug
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top