Operating System - OpenVMS
1827720 Members
3070 Online
109968 Solutions
New Discussion

Re: 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
Hein van den Heuvel
Honored Contributor

Re: how to DCL custom exit?

Thanks Bob,

I used a specific logical name table in order not to clutter my name space.

Cleanup is easy also, but maybe hard to find at first: $DEAS/TABLE=symbol/ALL

For interested readers that did not yet 'see' what I did here...

The SSDEF module and others in STARLET look like:
---------------
.MACRO $SSDEF,$GBL
$DEFINI SS,$GBL
; RIGHT: $EQU SYSTEM$_FACILITY 0
$EQU SS$_NORMAL 1
$EQU SS$_CONTINUE 1
:
---------------
Those first 3 lines are strictly for the Macro compiler and DCL does not like them.

But the rest, whilest actually being invocation of MACRO called "$EQU", look like fine DCL statements, if EQU was a command. The $EQU macro in macro translates to:
symbol = value
or
symbol == value
depending on the argument used for $SSDEF [GLOBAL|LOCAL|]

So I defined EQU in DCL as DEFINE and voila!
:-)

Hein
Robert Gezelter
Honored Contributor

Re: how to DCL custom exit?

Hein,

Actually, I was thinking of something a little more sparing of long term system resources.

As I said, I will put something together shortly that is easily usable by everyone.

- Bob Gezelter, http://www.rlgsc.com
Dean McGorrill
Valued Contributor

Re: how to DCL custom exit?

Hein, if this were my post, i'd give you 10's for that one! cute and useful Dean!
Hein van den Heuvel
Honored Contributor

Re: how to DCL custom exit?

On a roll here....

$ @symbol $SSDEF *acl*

SS$_ACLEMPTY = 2512 Hex = 000009D0 Octal = 00000004720
SS$_ACLFULL = 2552 Hex = 000009F8 Octal = 00000004770
SS$_BADACL = 3642 Hex = 00000E3A Octal = 00000007072
SS$_BADACLCTX = 8652 Hex = 000021CC Octal = 00000020714
SS$_IVACL = 8676 Hex = 000021E4 Octal = 00000020744
SS$_NOACLSUPPORT = 8892 Hex = 000022BC Octal = 00000021274


------- symbol.com ------
$IF p2.EQS."" THEN EXIT 16 !-)
$CREATE tmp.mar
$DECK
$ copy sys$input nl:
.MACRO $DEFINI dummy arg more_dummy
.ENDM
.MACRO $DEFEND dummy arg more_dummy
$ show symb arg
.ENDM
.MACRO $EQU nam num
$ nam = num
.ENDM
$EOD
$OPEN/APPEND tmp tmp.mar
$WRITE tmp "''p1' ''p2'"
$CLOSE tmp
$
$MACRO/ALPH/PREP=tmp.com tmp.mar
$@TMP
$DELE tmp.mar.,tmp.com.
-------------------------------------------

Hoff
Honored Contributor

Re: how to DCL custom exit?

Install the SDL kit off the OpenVMS Freeware V8.0 distro (VAX, Alpha and I64), or install a later version of SDL as available.

Invoke the following incantation...

$ LIBRARY/EXTRACT=SSMSG/OUT=SSMSG.SDI - SYS$LIBRARY:STARLETSD.TLB
$
$ SDL/NOPARSE/LANGUAGE=DCL
$
$ TYPE SSMSG.COM
...

SDL will extract the constant values -- and as DCL doesn't "do" data structures, much of what resides within the SDL Intermediate (SDI) file won't be propagated through -- and establish the DCL constants in an easy-to-include DCL command procedure.

Do use some caution here, as you might blow out and/or need to increase your DCL symbol table size if you are profligate with these "include files"...

Stephen Hoffman
HoffmanLabs LLC
Hoff
Honored Contributor

Re: how to DCL custom exit?

Correction:

$ LIBRARY/EXTRACT=SSMSG/OUT=SSMSG.SDI - SYS$LIBRARY:STARLETSD.TLB
$
$ SDL/NOPARSE/LANGUAGE=DCL SSMSG.SDI
$
$ TYPE SSMSG.COM
...

The filename on the SDL /NOPARSE was added.

BTW, SDL /NOPARSE starts with and processes the .SDI (intermediate) files. SDL /PARSE starts with and processes .SDL (source) files.
Claus Olesen
Advisor

Re: how to DCL custom exit?

Thank you for all the replies.

There is a lot of material in your replies to digest and choose from. I'm also looking forward to what Robert will put together.

The below is where I'm leaving what I started in the meantime. It works here but suffers from clutter most of which can be avoided by doing the lookup using DCL as you suggest as well as passing the cc value by DCL symbol as you also suggest.

The print bit in the cc is the reason for the rest of the clutter. I noticed from executing abc that the value of the print bit in the cc is sensitive to the way of exit. If the exit is by way of using dcl's exit i.e. "controlled" i.e. "on demand" (I suppose) then the print bit does not get set i.e. the cc does not get changed and/but a message is printed if error - as opposed to when DCL catches an exiting executable. so - to avoid "changing cc's" then always exit only by use of dcl's exit?

I looked for a callable (RTL) function to access *.TLB,*.MLB,*.OLB,*.HLB,...? Are there any?

-------------------
$! abc.com
$ emit:=$srv$exe:emit
$! get condition codes to test for later - siliently and without dying
$! msgflags = f$environment("MESSAGE")
$! set mess/nofac/nosev/noid/notext
$ set noon
$ emit SRV$_BADPARAM
$ status=$status
$ write sys$output "abc.1 ''status'"
$ cc1=f$integer(status)
$ emit SRV$_DEADLOCK
$ status=$status
$ write sys$output "abc.2 ''status'"
$ cc2=f$integer(status)
$ set on
$! set message 'msgflags'
$! execute some procedure also without dying
$ set noon
$ @xyz
$ status=$status
$ write sys$output "abc.3 ''status'"
$ status=status.and.%xfffffff
$ set on
$! now test the procedures exit status symbolically - the purpose of all of this
$ if status .eq. cc1
$ then
$ write sys$output "abc.4 cc1"
$ else if status .eq. cc2
$ then
$ write sys$output "abc.5 cc2"
$ endif
-------------------
$! xyz.com
$! cc print bit does not get set if error handling is disabled
$ set noon
$! mcr srv$exe:emit SRV$_BADPARAM
$ mcr srv$exe:emit SRV$_DEADLOCK
$! emit:=$srv$exe:emit
$! emit SRV$_BADPARAM
$ status=$status
$ write sys$output "xyz.1 ''status'"
$ exit status
-------------------
/* emit.c */
#include
#include
/* usage example: mcr srv$exe:emit SRV$_NORMAL */
int main(int argc,char *argv[])
{
int unsigned SymVal;
char FileName[80+1];
$DESCRIPTOR (dFileName,FileName);
$DESCRIPTOR (dSymName,"");

/* compose (system logical) name of our shareable */
sprintf(FileName,"%3.3sLIB",argv[1]);

dFileName.dsc$a_pointer=FileName;
dFileName.dsc$w_length=strlen(dFileName.dsc$a_pointer);
dSymName.dsc$a_pointer=argv[1];
dSymName.dsc$w_length=strlen(dSymName.dsc$a_pointer);

/* lookup symbol value */
lib$find_image_symbol(&dFileName,&dSymName,&SymVal);

return SymVal;

/* alternatively set symbol - this requires a CLI */
//lib$set_symbol(...);
}
-------------------
Hein van den Heuvel
Honored Contributor

Re: how to DCL custom exit?

>>> I looked for a callable (RTL) function to access *.TLB,*.MLB,*.OLB,*.HLB,...? Are there any?

Util routine manual...
Librarian (LBR) Routines

http://h71000.www7.hp.com/doc/83final/4493/4493pro_contents_001.html#toc_chapter_13


But, I dunno Claus... you lost me, and possibly you lost 'it'.

This smacks of overengineering to an extreme.

Just hardcode those defintions in the top of the script.

If you have more than say 5, then make yourself a command file to execute to defined the list of selected symbols.

LIB$FIND_IMAGE_SYMBOL is NOT a light system service. It opens file(s), reads, create memory sections, allocates VM calls LIB$INSERT_tree, for future lookups (which will nto happen in your case) and so on!

Just have DCL read that text file already! KISS!

Best of luck,
Hein.





Hoff
Honored Contributor

Re: how to DCL custom exit?

Over-engineering further, you can use libext to grab the whole contents of STARLETSD.TLB, and extract it all out and process it. libext is a component of the innards of an old C compiler installation environment -- this tool and some other DCL was used to create the C reference directories. libext is available on Freeware V7.0. It might also serve as an example of calling the LBR routines within the Librarian; see the utility routines reference manual for that detail.
Claus Olesen
Advisor

Re: how to DCL custom exit?

Just to summaries - what I had in mind is
- handling of condition codes symbolically in DCL
- automatic mask out of the control bits in the cc to eliminate comparison mismatches because of the control bits
- a library of messages dedicated to general use to avoid having to borrow codes from other facilities such as SS for use with for example RSH which doesn't return a code. Because if I receive an SS code then I should be able to rely on it originating from the "system" and not some other place out there like my DCL or my program.
Again, thank you for listening.
Robert Gezelter
Honored Contributor

Re: how to DCL custom exit?

Claus,

As a demonstration of how one aspect of this can be accomplished (e.g., being able to do something along the lines of:

$ EXITSTATUS "SS$_NOSUCHFILE"

I made available a simple command procedure that compiles a logical name table from the contents of the list of system error codes ($SSDEF in SYS$LIBRARY:STARLET.MLB) and a symbol definition for EXITSTATUS that uses this logical name table to convert from the symbolic name to the actual numeric value.

While I have not yet done so, it is straightforward to extend this to extend this with new codes and facility codes (to allow the use of the message facility).

This procedure is designed to be usable either by individual users within their processes, or it can be set up on a more global basis by system managers.

The ZIP archive of this example can be found at: http://www.rlgsc.com/demonstrations/exitstatus.html

- Bob Gezelter, http://www.rlgsc.com
Richard W Hunt
Valued Contributor

Re: how to DCL custom exit?

Just to take this in a different direction, I create a .MAR file that includes things like $SSDEF and $QIODEF and any other thing for which I need definitions. Assemble it with /LIST option.

When I want the condition codes, I run a little simple-minded parser that reads the listing with the right prefix (SS$_ for example) and picks out the values for me, then reformats it to something useful.

Like, for DCL it creates strings of

$ SS$_xxxx = %X{whatever I got from the file}

whereas for BASIC it does something else and for ADA it does still a third thing, in each case usable as an INCLUDE or syntax equivalent that is compatible with my language-du-jour.

Then the hardest issue becomes finding a message that tells me what I wanted to say from the list of messages available this way.

Sr. Systems Janitor
Hein van den Heuvel
Honored Contributor

Re: how to DCL custom exit?


Richard,

Why go through a list file and parse all that!
With a little less work, Macro can do it all:

For yucks run the commandfile below as:

$ @status_to_symbol.com $ssdef *priv*

---- status_to_symbol.com ------

$IF p2.EQS."" THEN EXIT 16
$CREATE tmp.mar
$DECK
$ copy sys$input nl:
.MACRO $DEFINI dummy arg more_dummy
.ENDM
.MACRO $DEFEND dummy arg more_dummy
$ show symb arg
.ENDM
.MACRO $EQU nam num
$ nam = num
.ENDM
$EOD
$OPEN/APPEND tmp tmp.mar
$WRITE tmp "''p1' ''p2'"
$CLOSE tmp
$
$MACRO/ALPH/PREP=tmp.com tmp.mar
$@TMP
$!DELE tmp.mar.,tmp.com.

A minor change will drop the 'search-for' argument and create global symbols.

And below here is a version which plunks the defintions into a logical name table
It also has some comments to the above to make it less cryptic. [ a few weeks ago I thought the few commands I write above simple enough, but coming back to them, they had me puzzled! ]

------------------- STATUS_TO_TABLE -----

$! STATUS_TO_TABLE.COM, hein van den Heuvel, Feb 2008
$! Define macro module symbols as logical names, using macro pre-processor
$!
$IF p1.EQS."" THEN EXIT 16 ! Need Macro module name to explode
$temp_macro_source = "TMP.MAR"
$temp_dcl_source = "TMP.COM"
$CREATE 'temp_macro_source ! Has replacements for $DEFINI and $DEFEND.
$DECK
$ copy sys$input nl: ! Eat bonus lines from macro compiler
.MACRO $DEFINI dummy arg more_dummy
.ENDM
.MACRO $DEFEND dummy arg more_dummy
$! show log/table=lnm_exit_status arg ! optional for inline show and forget
$ delete 'f$environment("procedure")',arg
$ copy sys$input nl: ! Eat blank bonus lines, avoiding %DCL-W-SKPDAT
.ENDM
.MACRO $EQU nam num
$define/tabl=lnm_exit_status nam num
.ENDM
$EOD
$
$temp_macro_source_full_spec = f$search(temp_macro_source)
$! Macro will strip ";". Replace by "."
$!temp_macro_source_full_spec = f$elem(0,";"tmp) + "." + f$elem(1,";"tmp)
$temp_macro_source_full_spec[F$LOC(";",temp_macro_source_full_spec),1] := "."
$
$!Append actual macro activation line to temporary macro source file.
$OPEN/APPEND tmp 'temp_macro_source
$WRITE tmp "''p1' ''temp_macro_source_full_spec'"
$CLOSE tmp
$
$MACRO/ALPH/PREP='temp_dcl_source 'temp_macro_source_full_spec
$@'temp_dcl_source



Enjoy!
Hein.