Operating System - OpenVMS
1747985 Members
4825 Online
108756 Solutions
New Discussion юеВ

undocumented "feature" of CLI$DCL_PARSE

 
Jess Goodman
Esteemed Contributor

undocumented "feature" of CLI$DCL_PARSE

I lost a lot of time because of this. A fairly complex program I was working on failed after relatively minor changes were made to it.

I eventually isolated the problem to a call to CLI$DCL_PARSE. Here is a short Fortran program that demonstrates the problem:

PROGRAM TEST
IMPLICIT NONE

INTEGER*4 STATUS, CLI$DCL_PARSE
EXTERNAL GET_INPUT, TEST_CLD

STATUS = CLI$DCL_PARSE( , TEST_CLD, , GET_INPUT, 'INPUT> ')
CALL EXIT(STATUS)
END

INTEGER*4 FUNCTION GET_INPUT( STRING, PROMPT, NC)
IMPLICIT NONE

CHARACTER STRING*(*)
CHARACTER PROMPT*(*)
INTEGER*2 NC

INTEGER*4 LIB$GET_INPUT

GET_INPUT = 1
NC = 0

DO WHILE (GET_INPUT .AND. NC.EQ.0)
GET_INPUT = LIB$GET_INPUT( STRING, PROMPT, NC)
ENDDO

RETURN
END

Or if you prefer C:

#include
#include
#include
#include

typedef struct dsc$descriptor_s StringDesc;

extern void *TEST_CLD;

int get_input( StringDesc *string, StringDesc *prompt, short *nc)
{
int status;

status = 1;
*nc = 0;

while ((status&1) && *nc==0)
status = LIB$GET_INPUT( string, prompt, nc);
return status;
}
int main()
{
int status;
$DESCRIPTOR( prompt, "INPUT> ");

status = CLI$DCL_PARSE( NULL, &TEST_CLD, NULL, get_input, &prompt);
return status;
}

If you compile either of these and LINK it with an object file created with SET COMMAND/OBJECT TEST.CLD

!TEST.CLD
define verb TEST
parameter P1, value(type=$rest_of_line)

Run the program and enter any string at the INPUT> prompt. This error occurs:

%RMS-F-USZ, invalid user buffer size

I tracked down the bug. CLI$DCL_PARSE calls the prompt_routine (its fourth argument) in the same manner that you would call LIB$GET_INPUT.

So the first argument to the prompt_routine is the address of a fixed-length string descriptor where the user input is to be returned.

And the third argument to the prompt_routine is the address of a word where the length of the user input is to be returned.

But CLI$DCL_PARSE passes the same address to the prompt routine for the first and third arguments!

In most cases this works out ok. When the returned length is written it updates the string descriptor by writing over the original (maximum) length of the string.

But as my Fortran/C examples show, if the program sets the return length argument to zero before passing on the string descriptor argument to another routine, then what gets passed on is a zero-length string!

This restriction is not documented and IMHO is a bug. I don't have software support, but if someone can tell me how to report this, or report it for me...TIA.

(Tested under VMS 7.3-2 - apologies if this was fixed by 8.3)
I have one, but it's personal.
2 REPLIES 2
John Gillings
Honored Contributor

Re: undocumented "feature" of CLI$DCL_PARSE

Jess,

Not "fixed" in V8.3 because, arguably, not broken!

This is a very common construct in OpenVMS. Note that string descriptor/length pairs occur in many routines, and the length is specifically defined "WORD, write only by reference", to allow updating the DSC$W_LENGTH field in a descriptor without overwriting the DSC$B_TYPE or DSC$B_CLASS fields. (This can cause the opposite problem if you pass a LONG variable and use it as the length without making sure the upper word is zero). RTL routines which deal with descriptors are all written so they work correctly with overlapping arguments.

That may seem odd in languages like Fortran or C which typically only deal with static descriptors, but it's perfectly natural for dynamic descriptors.

What might be considered a bug is the descriptor passed from CLI$ has no type or class fields (all zero), so you can't tell what kind of string you have.

When using descriptors to implement variable length strings, I tend to define a constant which remembers the maximum length, and let the DSC$W_LENGTH field float with the current length, by passing the descriptor as both string and length arguments, just like in your example. I need to remember to set the maximum length before the call, in order to avoid truncation errors.

In your code, you can do it like this:

maxstr=nc
repeat
nc=maxstr
status=lib$get_input(string,prompt,nc)
until status and (nc > 0)

(technically you should declare the string as a descriptor structure and read and write the DSC$W_LENGTH field instead of nc)

Although the CLI$ routine could be modified to pass separate arguments, and adjust the descriptor afterwards, your code shouldn't be making assumptions about non-overlapping arguments.
A crucible of informative mistakes
Hoff
Honored Contributor

Re: undocumented "feature" of CLI$DCL_PARSE

Clearly an OpenVMS software engineer took an expeditious (and easily arguably also entirely correct) approach with the coding around the static string descriptor (and the buffer) and the return length value argument propagated from within CLI$DCL_PARSE.

Ill-documented, but the call and the code does look like it's doing more or less what it should do and was intended to do here; you are taking control of and writing into a static string buffer here. Before you use the string descriptor.

I have a sneaking suspicion that if you were to look at the lib$get_input source code within the OpenVMS source listings, you'd probably find that it modifies the descriptor buffer first, and then sets the length. (This is a guess; I haven't checked the lib$get_input documentation or the source listings.)

It's this (latent) argument sequencing that would mean you're not following the cli$dcl_parse instructions for emulating the lib$get_input call.

Yes. Definitely obscure. Certainly Ill-documented. If you have a support contract, send a formal report over to OpenVMS Engineering and see what they say; whether they want to update or document this particular behavior, or extend the call to use two arguments, or what else the folks might decide.