Operating System - OpenVMS

how to DCL custom exit?

 
SOLVED
Go to solution
Claus Olesen
Advisor

how to DCL custom exit?

On Unix (Linux) there are formalized exit codes and simple messaging but no condition handling and typically 0 is success and anything else such -1 is error - AFAIK.

Consider this DCL
if ...
then
run sys$system:someprogram.exe
else
write sys$output "severe error"
exit ?
endif

if for whatever reason the command
run sys$system:someprogram.exe
fails then DCL will nicely exit right then and there with the system supplying the condition code that was the reason for the failure.

what to do in other cases i.e. when the cc is not given?
In the above - which cc should be chosen for the question mark?
At one time I hunted and think that I figured out that cc's starting here (in our systems)
"%X08AA0000" probably are free and safe to apply for custom use ("AA" is the facility identification).

So - the above exit could become
exit "%X08AA0000"

In response to that the DCL exithandler prints a NONAME message. Hmmm. Printing can be turned off by flipping bit
28 as in
exit "%X18AA0000"
or by turning off DCL exit handling or by disabling messages or by dumping messages to nla0:. But printing shouldn't be turned off, should it?

If the above DCL is invoked from another DCL and returns to it then you can test on exit status returned
using statements like
if $STATUS .eq. "%X08AA0000"
or
if $STATUS .eq. "%X18AA0000"

My point with all this is - it is not easy (error prone) nor pretty, is it?

What would be better I think is if you could say things like
if $STATUS .eq. SS$_ACCVIO

For that to work then one way would be to include long listings with contents like
SS$_ACCVIO = "%X0000000C"
...
in your DCL.

Not ideal either.

I think that what could be usefull is a lexical like this
cc=f$exit("SS$_ABORT")
to replace exits in DCL's?
I'm considering making a program to do just that.

The quick solution is to do as in Unix
exit 0
exit 1
But by doing that you are using a non-defined code - the "0"="%X00000000" - and one already defined by the the system "1"="%X00000001"=SS$_NORMAL (for system use only?).
Wouldn't a set of default codes for use for the "?" in above and supplied by OpenVMS be helpful?
So you in DCL could say for example
cc=f$exit("XXX$_BADPARAM")
where XXX$_ is a new facility for general use supplied by OpenVMS for use in quick whipups of DCL such that each and every user doesn't have to define such set?

One of our custom codes has the name SRV$_BADPARAM and the value "%X0803805A".
It is in one of our shareables pointed to by system logical SRVLIB.
if I run a test program that exits with that code the system prints
%SRV-E-BADPARAM ...
if I instead do this
exit("%X0803805A")
then the system prints
NONAME-E-NOMSG

I know that there is a message library path that you can append the path of your own message libraries to.
But I also saw this command
$ SET MESSAGE file

I tried it like this
$ set message SRVLIB
but get this error
%SYSTEM-F-IVSECIDCTL, invalid section identification match control
I'm curious. Anyone know the reason?
22 REPLIES 22
Dean McGorrill
Valued Contributor

Re: how to DCL custom exit?

hi, well there is a lexical that can help
you somewhat eg..

$ write sys$output f$message("%X0000000C")
%SYSTEM-F-ACCVIO, access violation, reason mask=!XB, virtual address=!XH, PC=!XH
, PS=!XL

$ write sys$output f$message("%X00000024")
%SYSTEM-F-NOPRIV, insufficient privilege or object protection violation

John Gillings
Honored Contributor
Solution

Re: how to DCL custom exit?

Claus,
Here's a little procedure which will find a condition value given a string or substring from the condition name.

MSGSYM.COM
$ IF p1.EQS."" THEN INQUIRE p1 "Message string"
$ PIPE LIBRARY/EXTR=$SSDEF/OUTPUT=SYS$OUTPUT SYS$SHARE:STARLET/MACRO | -
SEARCH SYS$PIPE "''p1'" | -
(READ SYS$PIPE s ; DEFINE/JOB/NOLOG msgdef &s 2>nl: >nl:)
$ def=F$EDIT(F$TRNLNM("MSGDEF"),"COMPRESS")
$ IF def.NES."%SEARCH-I-NOMATCHES, no strings matched"
$ THEN
$ 'F$ELEMENT(1," ",def)'=='F$ELEMENT(2," ",def)'
$ IF p2.NES."" THEN 'p2'=='F$ELEMENT(2," ",def)'
$ ELSE
$ WRITE SYS$OUTPUT "''p1' not found"
$ ENDIF

As coded it defines a global symbol using the condition name, given the condition value. For example:

$ @msgsym accvio
$ show sym ss$_accvio
SS$_ACCVIO == 12 Hex = 0000000C Octal = 00000000014

If you give it a P2 parameter, it will define that name as a global symbol using the same value.

I've attached a procedure that does the same job, but instead of defining a global symbol, it returns the status code as $STATUS (with the "nodisplay" bit set so no message is generated). Instead of searching STARLET every time, I've extracted the values and converted them to DCL assignment statements (this would need to be redone for a later version of OpenVMS). If you enter an ambiguous message name, the lowest condition code value with a matching name is returned. If no matching value is found, $STATUS is set to %X10000000.

$ @ssdef accvio
$ show sym $status
$STATUS == "%X1000000C"
$ @ssdef dev
$ show sym $status
$STATUS == "%X10000064"
$ write sys$output f$message("%X10000064")
%SYSTEM-F-DEVFOREIGN, device is mounted foreign
$ @ssdef nomsg
$ show sym $status
$STATUS == "%X10000000"
A crucible of informative mistakes
Steven Schweda
Honored Contributor

Re: how to DCL custom exit?

I suspect that most status codes are
generated by actual executable programs, not
directly in DCL, so the lack of features in
this neighborhood is not seen as a big
problem.

> In response to that the DCL exithandler
> prints a NONAME message. Hmmm. [...]

With a suitable message file, and the use of
SET MESSAGE, it _could_ say almost anything
you'd like.

> I tried it like this
> $ set message SRVLIB
> but get this error
> %SYSTEM-F-IVSECIDCTL, invalid section
> identification match control
> I'm curious. Anyone know the reason?

SRVLIB was, perhaps, not constructed as the
right kind of message file (MESSAGE /OBJECT,
LINK /SHAREABLE). After some activity a
while ago, my grasp on the details here is
fading, but I thought that I had it figured
out well enough (once) that the next versions
of UnZip and Zip should have their own
message codes and messages. Of course,
again, those are programs, not DCL
procedures.

http://h71000.www7.hp.com/doc/82final/6100/6100pro_009.html#msg_chap
John Gillings
Honored Contributor

Re: how to DCL custom exit?

back to your original question...

you can define your own facility and condition codes - see the message compiler "HELP MESSAGE". There is a range of facility codes reserved for customer use. Once you've compiled your message definitions, use SET MESSAGE to make them available to DCL.

I don't have a copy of SRVLIB so can't try to reproduce your IVSECIDCTL message. I remember coding around that error in my procedure to find the text associated with a message code, but never worked out why some message files do it. According to HELP/MESSAGE it indicates a bug in the image.

>exit 0
>exit 1
>But by doing that you are using a
>non-defined code - the "0"="%X00000000" -
>and one already defined by the the
>system "1"="%X00000001"=SS$_NORMAL (for
>system use only?).

You're free to use any exit codes, including those that aren't defined, BUT remember that DCL will automatically generate a message if the low bit is clear. You can prevent that by setting bit 28:

$ exit %X10000000.OR.yourvalue

Conversely you need to remember that any condition code you receive is really a bit structure, so you should (at least) mask off the top nibble (control bits) before doing any EQ comparisons because you won't know in advance which, if any of the control bits are set, and their values don't change the meaning of the condition code:

$ IF ($STATUS.AND.%XFFFFFFF).EQ.SS$_somevalue THEN...

Have a read through the MESSAGE utility documentation "HP OpenVMS Command Definition, Librarian, and Message Utilities Manual", and the programming concepts manual. You can do many interesting things with condition codes once you understand how they work.
A crucible of informative mistakes
Claus Olesen
Advisor

Re: how to DCL custom exit?

Thanks John.
That was fast.

This is how far I've come since posting
#include
#include

int main(int argc,char *argv[])
{
int unsigned SymVal;
$DESCRIPTOR (dImgFileName,"");
$DESCRIPTOR (dSymName,"");
$DESCRIPTOR (dImgDirName,"");
struct dsc$descriptor_s *pdImgDirName=0;

dImgFileName.dsc$a_pointer=argv[1];
dImgFileName.dsc$w_length=strlen(dImgFileName.dsc$a_pointer);

dSymName.dsc$a_pointer=argv[2];
dSymName.dsc$w_length=strlen(dSymName.dsc$a_pointer);

if (argc==3)
{
pdImgDirName=0;
}
else
{
dImgDirName.dsc$a_pointer=argv[3];
dImgDirName.dsc$w_length=strlen(dImgDirName.dsc$a_pointer);
pdImgDirName=&dImgDirName;
}
lib$find_image_symbol(&dImgFileName,&dSymName,&SymVal,pdImgDirName);
printf("%x\n",SymVal);

return 1;
}
It works on our custom shareables with custom codes but not the OpenVMS ones such as SS$_NORMAL because lib$find_image_symbol doesn't like anything but *.exe's I think.

Thanks for the procedure. I'll will check it out.

Good point that clearing of the control bits is needed as in
$ IF ($STATUS.AND.%XFFFFFFF).EQ.SS$_somevalue THEN...
But it doesn't make it any easier to deal with, does it?

Thanks Steven,
"SRVLIB was, perhaps, not constructed as the
right kind of message file (MESSAGE /OBJECT,
LINK /SHAREABLE)."
Our shareables contain both program code and messages. Perhaps the "SET MESSAGE file" command does not like that. I have not tested for that yet.
John Gillings
Honored Contributor

Re: how to DCL custom exit?

Claus,

>Our shareables contain both program code and messages

Should be relatively easy to fix. Rather than linking your messages into the image, you need an extra level of indirection.

Compile and link your messages into a shareable image that contains only messages, then link your other images against. I think they're called "Message Pointers" or similar. See the Message Utility documentation.

There are several advantages - you can easily change message definitions (for example, if you ever need to produce a version of your programs in another [human]language) or even to correct simple typos in the message text. You can also share the same message definitions across multiple images, and you have "external" access to the messages via SET MESSAGE.

Oh, and I didn't realise you wanted your conversion to work for ALL message files. The procedures I posted only work for system messages ($SSDEF), but the principles are applicable to other facilities, assuming you can work out which macro defines the codes.

For your C program, you could create an SSMSG to access all the SS$_ codes, or build in a special case that checks against the codes as defined by the C include file equivalent of $SSDEF.
A crucible of informative mistakes
Robert Gezelter
Honored Contributor

Re: how to DCL custom exit?

Claus,

As has been noted, there exist a standard set of error codes, in $SSDEF. Depending upon what languages have been installed, there are a series of include files in SYS$LIBRARY, contained in TLB files.

If you are writing a program to emit the completion code using a standard search string, I would recommend the following:

As an underlying default, use the list of error codes in $SSDEF. Before using that underlying default, I would check for a logical, say ERROREMIT_MESSAGELIST, which would point to a file (or files) containing a list of specific errors. I would have to think where I would put this logical, some places are far, far better than others.

Then, the combination of SET MESSAGE and the newly defined EMIT_STATUS("string") image would be well integrated.

My apologies if my description is not as cogent as it could be, I am writing this after relatively little thought.

- Bob Gezelter, http://www.rlgsc.com
Hein van den Heuvel
Honored Contributor

Re: how to DCL custom exit?

Claus,

Too bad really that HELP/MESS does not provide the numeric values allong with explanation huh?

I've had the same thoughts about using symbolic exit value to convey a specific message at times.
But I found it was only applicable to a few symbols, typically SS$_BADPARAM, and just looked up the value for those symbols from a handy file in my directory or with a command similar to the one already shown:

For exampe:

$ pipe libr/extr=$ssdef/out=sys$output sys$library:starlet.mlb | sea sys$pipe ACLEMPTY
$EQU SS$_ACLEMPTY 2512
$


The LIB$FIS method you suggest can be done, but not with files currently present on the system. Check this:

$ cre tmp.mar
$ssdef GLOBAL
.end
$ mac tmp
$ link/share/map tmp,tt:/opt
SYMBOL_VECTOR=(SS$_ACLFULL=DATA,SS$_ACLEMPTY=DATA)
$ fis :== "$dev:[dir]fis " ! Claus program
$ fis dev:[dir]TMP SS$_ACLEMPTY
%SYSTEM-F-IVLOGNAM, invalid logical name
$ def xxx dev:[dir]TMP
$ fis xxx SS$_ACLEMPTY
9d0
$ fis xxx SS$_ACLFULL
9f8

So you'd have to go through all this trouble to make a special file, albeit an image. You might as well just search the library, or maybe even extract them all for once and all and stick them in flat or indexed text file.

Finally, just to be cute, and for no practical purpose you could use:

$ crea/name symbol
$ equ =="define/table=symbol "
$ libr/extr=$ssdef/out=tmp.tmp sys$library:starlet.mlb
$ define/user sys$error nl:
$ define/user sys$output nl:
$ @tmp.tmp
$ show log *acl*/table=symbol

(SYMBOL)

"SS$_ACLEMPTY" = "2512"
"SS$_ACLFULL" = "2552"
"SS$_BADACL" = "3642"
"SS$_BADACLCTX" = "8652"
"SS$_IVACL" = "8676"
"SS$_NOACLSUPPORT" = "8892"

grins,
Hein.

Robert Gezelter
Honored Contributor

Re: how to DCL custom exit?

Hein,

I would not go so far as "no practical purpose".

Combining your observation with my earlier comment, and using the ability of F$TRNLNM to search a specific logical name table, you could get almost precisely the functionality requested.

If people are interested in this approach, I will try to gin something up when I get off of my current urgent deadline.

- Bob Gezelter, http://www.rlgsc.com