If you see a section containing the placeholder {TBS} (To Be Supplied) and feel an urge to fill that gap, please do so. Also, if you see any incorrect information, drop me a mail.
Though Digital Equipment Corporation (DEC) is no more, this name is used throughout this document. Some products may by now go under a name that starts with "HP" or "Compaq" instead of "DEC" or "Digital".
DEC, Digital, Compaq, HP and/or other HP products referenced herein are either trademarks or registered trademarks of Hewlett-Packard. Other product and company names mentioned herein may be the trademarks of their respective owners.
This document was last compiled from underlying sources on Fri Jun 5 08:29:15 2009.
2. Language Specifics
2.1. Programming in C
2.1.1. Where are the system header files for C?
2.1.2. The Calling Standard in C
2.1.3. VAX C and DEC C, and other C Programming Considerations
2.1.4. How to get prototypes for system services
2.1.5. How to use the VMS v7 C RTL under VMS v6
2.1.6. Traps and Pitfalls in C
2.2. Programming in Pascal
2.2.1. Where are the system header files for Pascal?
2.2.2. The Calling Standard in Pascal
2.3. Programming in Fortran
2.3.1. Where are the system header files for Fortran?
2.3.2. The Calling Standard in Fortran
2.4. Programming in BLISS
2.4.1. Where are the system header files for BLISS?
2.4.2. The Calling Standard in BLISS
2.4.3. Compiler can't find SYS$LIBRARY:STARLET.L32
2.5. Programming in BASIC
2.5.1. Where are the system header files for BASIC?
2.5.2. The Calling Standard in BASIC
2.6. Programming in MACRO
2.6.1. Where are the system header files for MACRO?
2.6.2. The Calling Standard in MACRO
3. How Do I ...?
3.1. ...create a program source file?
3.2. ...compile a program source file?
3.3. ...link a program?
3.4. ...link against a shareable image?
3.5. ...build a shareable image?
3.6. ...debug an application?
3.7. ...get F$EDIT
functionality from a program?
3.8. ...validate a user's password?
3.9. ...debug an application that uses the terminal, or a detached application?
3.10. ...get info from the command line? Do I need to parse it myself?
3.11. ...get the DCLTABLE verb a program was called by?
3.12. ...get info about the DECwindows display?
3.13. ...program a deterministic automaton?
3.14. ...get the value of an unknown symbolic condition code?
4. Porting Software from Unix
4.1. Converting a Unix Makefile
to a DESCRIP.MMS
4.2. Libraries to Aid Porting
4.3. Links to Other Porting Resources
5. DCL Tips & Tricks
5.1. Getting the date from a binary quadword value
5.2. Producing a random number
5.3. Computing the julian day number
5.4. Toggling an image's debug bit
5.5. Computing the first and the last day of a month
5.6. Tricks with F$VERIFY()
5.7. Finding the name of the calling procedure
5.8. Generating a password
5.9. Getting the elapsed time
5.10. Sorting DIRECTORY
by modification date
5.11. Getting the /LOG value from within a batch job
5.12. Getting the next available UIC
5.13. Validating a date of format dd-mm-yyyy
5.14. Determining whether a process with a given PID exists
5.15. Testing for a leap year
5.16. Opening a mailbox (e.g. for IPC)
6. Resources
6.1. OpenVMS Programming Documentation
6.2. OpenVMS FAQ
6.3. DJE VMS mentor pages
6.4. Arne Vajhoej's pages
6.5. OpenVMS Freeware CD
6.6. How to Write a Native VMS Command
6.7. DCL resources
make
under Unix. Some
caveats apply, though (some of them are described in the section
"Converting a Unix Makefile
to a DESCRIP.MMS
")make
diff
and patch
(available e.g. from http://www.crinoid.com/utils/)AACRTL060
, which can be used to install
VMS v6 C programs under VMS v5.5 (where the DEC C RTL isn't included).
$service
,
but mostly must be called from High Level Languages as SYS$service
.
$HELP System_Services
and
$HELP RTL_Routines
.
See the "Access" and "Mechanism" points in the section "The system API" for common parameter types and calling mechanisms.
For further information on how the Calling Standard is implemented
in various languages, see
"The Calling Standard in BASIC",
"The Calling Standard in BLISS",
"The Calling Standard in C",
"The Calling Standard in Fortran",
"The Calling Standard in MACRO", and
"The Calling Standard in Pascal".
Named constants for condition values of the various facilities are in *DEF.xxx
system header/include/PEN files (e.g. for C, SSDEF.H
for system services,
LIBDEF.H
for the LIB$ routines, SHRDEF.H
for codes shared by various facilities, etc.).
See Symbolic Names Nomenclature.
As the severity and/or facility could vary, a returned condition code
value should not be compared for equality to some constant, but checked
against a message number using the LIB$MATCH_COND
routine.
All system messages, complete with cause and action to take, are described in
the "Error Codes And Recovery Procedures" manual; the $HELP/MESSAGE
error
DCL command provides an online interface to these (VMS 6 and later);
under VMS 5.5, the information can be accessed by HELP @SYSMSGHELP error
.
VMS has a very standard nomemclature to name field and constants in compiler/language modules:
fac$x_yyyyyyywhere fac denotes the facility, yyyyyy denotes the name, and the x denotes the type of data (and implicit size of value):
A descriptor is a data structure that describes a string or an array. Each descriptor contains information that describes the type of the data being referenced, the size of the data, and the address of the data. It also includes a description of the storage used for the data, typically static or dynamic. Descriptors are passed by reference.
The following are examples of creating and using descriptors in C:
#include <descrip.h> #include <lib$routines.h> #include <stsdef.h> int RetStat; char TxtBuf[TXTSIZ]; struct dsc$descriptor StaticDsc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; struct dsc$descriptor DynDsc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL }; int DynDscLen = 255; $DESCRIPTOR( ConstDsc, "This is a string" ); /* finish setting up a static descriptor */ StaticDsc.dsc$w_length = TXTSIZ; StaticDsc.dsc$a_pointer = (void *) TxtBuf; /* finish setting up a dynamic descriptor */ RetStat = lib$sget1_dd( &DynDscLen, &DynDsc ); if ( !$VMS_STATUS_SUCCESS( RetStat ) ) return RetStat; /* release the dynamic storage */ RetStat = lib$sfree1_dd( &DynDsc ); if (!$VMS_STATUS_SUCCESS( RetStat )) return RetStat;
Static descriptors reference storage entirely under application program control, and the contents of the descriptor data structure can be modified as required (by the application). OpenVMS routines do not modify the contents of a static descriptor, nor do they alter the address or length values stored in the static descriptor. (The term "static" refers to the descriptor data structure, and not necessarily to the storage referenced by the descriptor.)
Dynamic descriptors reference storage under the control of the run-time library, and the contents of a dynamic descriptor data structure - once initialized - can only be modified under control of run-time library routines. The dynamic storage referenced by the dynamic descriptor is allocated and maintained by the run-time library routines. Various OpenVMS routines do alter the contents of the descriptor data structure, changing the value for the amount and the address of the storage associated with the dynamic descriptor, as required. Routines can obviously access and alter the contents of the storage referenced by the descriptor.
OpenVMS languages that include support for strings or arrays are expected to use descriptors for the particular structure. Most OpenVMS languages, such as Fortran and BASIC, use descriptors entirely transparently. Some, like DEC C, require the programmer to explicitly create and maintain the descriptor.
For further information on string descriptors, see the OpenVMS Programming Concepts manual, part of the OpenVMS documentation set.
Fortran defaults to passing integers by reference and characters by descriptor. The following sites discuss mixing Fortran and C source code in the same application:
Also see the section about "The Calling Standard".
The IOSB consists of a 16bit word holding the number of bytes transfered, a 16bit word holding the condition value describing the I/O operation's completion status, and additional information (dependant on the operation and the device).
It should always be used with asynchronous operations, because
the condition value returned from the system routine only refers to the
queuing of the operation, while the actual result of the operation is
passed in the IOSB.
SYS$LIBRARY:
.
DEC C uses, for performance reasons, the library SYS$LIBRARY:DECC$RTLDEF.TLB
.
At installation time, there's an option to install reference copies in
SYS$SYSROOT:[DECC$LIB.REFERENCE...]
(though those are not used in compilation!).
The header file for system services is called STARLET.H
, library
routines are declared in various *$ROUTINES.H
headers. Other
definitions reside in *DEF.H
files.
<descrip.h>
has types and macros to deal
with descriptors.
dsc$descriptor_s
VAX C V3.2 was released for OpenVMS VAX systems in 1991. DEC C V4.0 replaced VAX C V3.2 in 1993 as the HP C compiler for OpenVMS VAX systems. HP C is the ANSI C compiler for OpenVMS Alpha systems. VAX C predates the ANSI C standards, and has various areas that are not compliant with ANSI C requirements. HP C is an ANSI C compiler, and can also compile most VAX C code when /STANDARD=VAXC is specified. Versions of this compiler between V3.2 and V6.5 (exclusive) were known as DEC C, DIGITAL C, and Compaq C.
Both compilers can be installed at the same time on the same OpenVMS VAX system, allowing a migration from VAX C to DEC C, and allowing the same DEC C code to be used on OpenVMS VAX and OpenVMS Alpha.
The system manager can choose the system default C compiler when HP C is installed on a system with VAX C, and a C programmer can explicitly select the required compiler for a any particular compilation.
A current "C" license PAK allows access to both VAX C and HP C on the same OpenVMS VAX system.
Various HP C versions can be installed on OpenVMS VAX V5.5-2 and later. OpenVMS VAX releases such as V5.5-2 and V6.0 will require the installation of a HP C RTL kit, a kit that is included with the HP C compiler. OpenVMS VAX versions V6.1 and later do not require a seperate RTL kit, but HP C RTL ECO kits are available to resolve problems found with the C RTL on various OpenVMS releases.
With HP C, for automatic resolution of the standard C library routines
by the LINKER utility, use the /PREFIX
qualifier, such as
/PREFIX=ALL_ENTRIES
. If a particular application program replaces an
existing C library routine, use /PREFIX=(ALL_ENTRIES,EXCEPT=(...))
.
(VAX C required explicit specification of an RTL shareable image or C
object library during the link.)
When the /PREFIX
is requested, the compiler generates a decc$
prefix
on the specified symbols. This prefix allows the LINKER to resolve the
external symbols against the symbols present in the DECC$SHR library.
The DECC$SHR library is included in the IMAGELIB.OLB
shareable image
library, and IMAGELIB is searched by default when any program (written
in any language) is LINKed. Because the standard C library routine
names are very likely to match application routines written in other
languages, a prefix decc$
is added to the C symbol names to assure
their uniqueness; to prevent symbol naming conflicts. C programs,
however, can sometimes have private libraries for various purposes, and
the external routines share the same names as the library routines.
(This is not recommended, but there are applications around that use
this technique.) Thus the need to explicity specify whether or not the
decc$
prefix should be prepended to the external symbol names by the
compiler.
The qualifiers, and most (all?) with associated pragmas, that may be of interest when migrating VAX C code to HP C include:
/PREFIX=ALL_ENTRIES
/ASSUME=WRITABLE_STRING_LITERALS
/SHARE_GLOBALS
/EXTERN_MODE=COMMON_BLOCK
/[NO]MEMBER_ALIGNMENT
Permit structure members to be naturally aligned whenever possible, and
avoid using /NOMEMBER_ALIGNMENT
. If you need to disable member
alignment, use the equivilent #pragma
to designate the specific
structures. The alignment of structure members normally only comes into
play with specific unaligned data structures - such as the sys$creprc
quota itemlist - and with data structures that are using data that was
organized by a system using byte or other non-member alignment.
Versions of HP C such as V6.0 include the capability to extract the
contents of the standard header libraries into directories such as
SYS$SYSROOT:[DECC$LIB...]
, and provide various logical names that can
be defined to control library searches. With HP C versions such as
V6.0, the default operations of the compiler match the expectations of
most OpenVMS programmers, without requiring any definitions of
site-specific library-related logical names. (And logical names left
from older DEC C versions can sometimes cause the compiler troubles
locating header files.)
HP C V5.6 and later include a backport library, a mechanism by which HP C running on older OpenVMS releases can gain access to newer RTL routines added to the RTL in later OpenVMS releases - the language RTLs ship with OpenVMS itself, and not with the compilers.
Example C code is available in SYS$EXAMPLES:
, in DECW$EXAMPLES:
(when
the DECwindows examples are installed), in TCPIP$EXAMPLES:
(or on older
releases, UCX$EXAMPLES:
) when HP TCP/IP Services is installed), on the
OpenVMS Freeware CD-ROMs, and at web sites such as
__NEW_STARLET
to 1 before including any system header files results in prototyped
functions. There are, however, problems with certain types
in the supplied prototypes (most notably quadwords).
$ define decc$crtlmap sys$library:decc$crtl.exe $ define lnk$library sys$library:decc$crtl.olbIt becomes necessary to use this functionality when the declaration of functions in the header files is conditionalized by
#if __CRTL_VER >= 70000000 ... #endifHowever, using this of course bars the application from taking advantage of bugfixes in newer versions of the RTL.
Beware that the Unix time functions that use timezone information
(e.g. tzset()
) and I18N features are not supported pre-VMS v7.
The documentation for this feature is in SYS$LIBRARY:DECC$CRTL.README
.
$DESCRIPTOR
macro from <descrip.h>
stores the length of the character string using sizeof()
.
It is thus only suitable for use with character arrays and string literals,
but not for use with char*
.void sub(char str[]) { $DESCRIPTOR(str_dsc, str); ...
str_dsc.dsc$w_length
is 3 (== sizeof(char*)-1
),
and not sizeof(str)-1
.
SYS$LIBRARY:STARLET.L32
LIBRARY 'SYS$LIBRARY:STARLET'; ........^ %BLS32-E-M_OPENIN, error opening SYS$LIBRARY:STARLET as input -RMS-E-FNF, file not found
Solution: Build STARLET.L32
and LIB.L32
:
$ SET DEFAULT SYS$COMMON:[SYSLIB] $ BLISS /LIBRARY STARLET.REQ $ BLISS /LIBRARY=LIB.L32 STARLET.REQ+LIB.REQ
(This is done during BLISS installation on a VAX system.)
F$EDIT
functionality from a program?
I've always used BAS$EDIT
for that purpose. On Alpha/VMS,
BASRTL
is replaced by DBASIC$RTL
.
The following C program shows how to call EDIT on both platforms
(tested with DECC 5.0 on Vax/VMS 6.1, Alpha/VMS 6.1).
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <descrip.h> #include <stsdef.h> #pragma nostandard #define MAX_STR_LENGTH 250 typedef struct dsc$descriptor_vs vs_descr; #define VS_STRING(name,len) struct { \ short length; \ char body[len]; \ vs_descr descr; \ } name = {0,"",{len,DSC$K_DTYPE_VT,DSC$K_CLASS_VS,(char*)&name.length}} #define STRING(name) VS_STRING(name,MAX_STR_LENGTH) #ifdef __alpha #define EDIT DBASIC$EDIT #else #define EDIT BAS$EDIT #endif extern int EDIT (vs_descr *tgt, vs_descr *src, int flags); #define EDIT_DISCARD_PARITY 1 /* Discards bit 7 */ #define EDIT_COLLAPSE 2 /* Discards spaces and tabs */ #define EDIT_DISCARD_FORMS 4 /* Discards cr, lf, ff, del, esc and nul */ #define EDIT_TRIM 8 /* Discards leading and trailing spaces and tabs */ #define EDIT_COMPRESS 16 /* Compresses multiple spaces and tabs to single spaces */ #define EDIT_UPCASE 32 /* Converts lowercase to uppercase */ #define EDIT_UNBRACKET 64 /* Converts [ and ] to ( and ) */ #define EDIT_TRAIL 128 /* Discards trailing spaces and tabs */ #define EDIT_QUOTE 256 /* Preserves characters within quotes */ main() { int sts; STRING(st1); STRING(st2); (void) printf("Str1: "); (void) gets(st1.body); st1.length = strlen(st1.body); sts = EDIT(&st2.descr, &st1.descr, EDIT_COMPRESS | EDIT_TRIM | EDIT_UPCASE | EDIT_QUOTE); if (!$VMS_STATUS_SUCCESS(sts)) { lib$signal(sts); exit(EXIT_FAILURE); } st2.length = strlen(st2.body); (void) printf("st2= '%s'\n", st2.body); } #pragma standard
/* ** int validate_account( const char *username, const char *password ) ** ** if username == NULL or empty, gets the current username ** ** Condition values returned: ** SS$_NORMAL - account validated ** SHR$_VALERR - account validation failed ** (BTW: anyone know a method of finding a decent condition code ** given a condition it should match?) ** any condition codes indicating an error returned by ** STR$UPCASE, LIB$GETJPI, $GETUAI, $HASH_PASSWORD */ #include <stdlib.h> #include <string.h> #include <ctype.h> #define __NEW_STARLET 1 #include ssdef #include shrdef #include stsdef #include jpidef #include uaidef #include descrip #include starlet #include lib$routines #include str$routines #define USERNAME_MAX 12 #define PASSWORD_MAX 32 /* == CIA$K_PASSWORD_MAX_LENGTH on recent VMS versions */ typedef struct { unsigned short buflen; unsigned short itemcode; void *bufadr; unsigned short *lenadr; } item_list_3; typedef struct { int lo, hi; } quadword; #ifdef __DECC # pragma message disable (ADDRCONSTEXT,NOTCONSTQUAL) #endif #define CHKCOND(st) { \ int chkcond_stat = (st); \ if (!$VMS_STATUS_SUCCESS(chkcond_stat)) \ return chkcond_stat; \ } static int mystr2dsc( struct dsc$descriptor_s *dsc, const char *src ) { size_t l = strlen( src ); if (l < dsc->dsc$w_length) dsc->dsc$w_length = l; strncpy( dsc->dsc$a_pointer, src, l ); return STR$UPCASE(dsc, dsc); } int validate_account( const char *username, const char *password ) { char usr[USERNAME_MAX]; char pwd[PASSWORD_MAX]; $DESCRIPTOR(usr_dsc, usr); $DESCRIPTOR(pwd_dsc, pwd); unsigned char alg; unsigned short salt; quadword hash, uai_hash; item_list_3 uai_itmlst[] = { { sizeof(alg) , UAI$_ENCRYPT, &alg , NULL }, { sizeof(salt) , UAI$_SALT , &salt , NULL }, { sizeof(uai_hash), UAI$_PWD , &uai_hash, NULL }, { 0, 0, NULL, NULL } }; if (username == NULL || *username == '\0') { int item_code = JPI$_USERNAME; char *p; unsigned short l; CHKCOND( LIB$GETJPI(&item_code, NULL,NULL,NULL, &usr_dsc, NULL) ); /* The returned username is blank-padded; find length */ for (p = usr, l = 0; (isalnum(*p) || *p == '$' || *p == '_') && l < USERNAME_MAX; ++p, ++l) ; usr_dsc.dsc$w_length = l; } else { CHKCOND( mystr2dsc(&usr_dsc, username) ); } CHKCOND( mystr2dsc(&pwd_dsc, password) ); CHKCOND( SYS$GETUAI(0L,NULL, &usr_dsc, uai_itmlst, 0L,0L,0L) ); CHKCOND( SYS$HASH_PASSWORD(&pwd_dsc, alg, salt, &usr_dsc, &hash) ); return (memcmp(&hash, &uai_hash, sizeof(quadword)) == 0) ? SS$_NORMAL : SHR$_VALERR; } #ifdef TEST #include <stdio.h> int main( int argc, char *argv[] ) { char username[USERNAME_MAX+1], password[PASSWORD_MAX+1]; int result; printf("Username: "); gets(username); printf("Password: "); gets(password); result = validate_account(username, password); if ($VMS_STATUS_SUCCESS(result)) { printf("Account validated\n"); } else { char msg[1024]; $DESCRIPTOR(msg_dsc, msg); unsigned short msg_len = 0; SYS$GETMSG( result, &msg_len, &msg_dsc, 0x0F, NULL ); msg[msg_len] = 0; printf( "Account validation failed:\n%s\n", msg ); } } #endif /* TEST */
$ CREATE /TERMINAL /NOPROCESS - _$ /DEFINE_LOGICAL=(TABLE=LNM$GROUP,DBG$INPUT,DBG$OUTPUT) - _$ /WINDOW_ATTRIBUTES=(TITLE="Debugger",ICON_NAME="Debugger") - _$ /LITTLE_FONT
_LTAx:
):
$ SET PROCESS /PRIVILEGE=(LOG_IO) $ SET TERMINAL /NOHANGUP /PERMANENT $ LOGOUT /NOHANGUPAlternatively: There is a bit (MODHANGUP, value 8) in the
TTY_DEFCHAR2
system parameter that allows modification
of the HANGUP
characteristic without privileges.
With that set, a simple
$ SET TERMINAL /NOHANGUP $ LOGOUT /NOHANGUPsuffices.
On the program-terminal-to-be:
$ ! The following two commands are only needed if _LTAx:
$ ! isn't set up to allow general access
$ SET PROCESS /PRIVILEGE=(OPER,LOG_IO)
$ SET PROTECTION=(W:RW) /DEVICE _LTAx: ! or set an ACL granting you access
$
$ ALLOCATE _LTAx:
$ DEFINE DBG$INPUT _LTAx:
$ DEFINE DBG$OUTPUT _LTAx:
$ SET TERMINAL /DEVICE=VT200 /PERMANENT _LTAx:
$ !... run program to be debugged
$ DEALLOCATE _LTAx:
Feeding the special label $VERB
to the CLI$GET_VALUE
routine gives you the verb.
There are undocumented and unsupported itemcodes that one can `aim' at
the DECW$DEVICE
(WSAn:) device. The core C code looks like this:
#define IO$M_WS_DISPLAY 64 #define DECW$C_WS_DSP_NODE 1 #define DECW$C_WS_DSP_TRANSPORT 2 #define DECW$C_WS_DSP_SERVER 3 #define DECW$C_WS_DSP_SCREEN 4 RetStat = sys$qiow( Ef, Chan, IO$_SENSEMODE|IO$M_WS_DISPLAY, IosbPtr, 0, 0, NodeBufferPtr, NodeBufferSize, DECW$C_WS_DSP_NODE, 0, 0, 0 );The Digital Customer Support Centers (CSCs) should have one or more full example programs available online.
Standard disclaimers apply: this interface is undocumented, unsupported
and subject to change without notice, etc.
LIB$TPARSE
for VAX, and LIB$TABLE_PARSE
for Alpha. Implementing the state table is easily done only from MACRO or BLISS.
Some condition codes don't show up in the *DEF.H
files. If
the shareable image that houses them is known, you can get to them by
SDA, e.g. to find the numeric value of LBR$_ILLFMT
in SYS$LIBRARY:LBRSHR.EXE
:
$ ANALYZE /SYSTEM SDA> READ /IMAGE SYS$LIBRARY:LBRSHR.EXE %SDA-I-READSYM, 78 symbols read from SYS$COMMON:[SYSLIB]LBRSHR.EXE;3 SDA> SET OUTPUT LBRMSGDEF.LIS SDA> SHOW SYMBOL /ALL LBR$_ SDA> EXIT $ TYPE LBRMSGDEF.LIS ... LBR$_ILLIDXNUM = 00000000.00269022 : 4D414E47.4D495F54 LBR$_ILLFMT = 00000000.0026902A : 00000000.0000435F LBR$_ILLFUNC = 00000000.00269032 : 00000000.00000000 ... $ EXIT %X0026902A %LBR-E-ILLFMT, illegal library format
Makefile
to a DESCRIP.MMS
:
" separating targets and prerequisites
by "<blank>:
" (because under VMS, ":
"
is a legal filespec character).
.exe
".$(CC)
" without "-c
".-c
"s hidden in macros!)
.o
" by ".obj
".
$(MAKE)
" by "$(MMS)
".
Or define a DCL symbol to equate MAKE
to MMS
.
$(CC)
is used for both compiling and linking:$(CC) -c
" by "$(CC)
", and
"$(CC)
" without "-c
" by "$(LINK)
"
when applied to an object file; when applied to a source file, replace it by two action lines.
CC
macro by something appropriate (e.g. "CC/DECC
")./PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
".
,
".OBJS = a.o b.o c.o
").
The VMS Linker can cope with blank-separated lists, though./DEFINE
" qualifiers
(or more accurately, it only uses the last "/DEFINE
" qualifier),
so one has to gather all "-D
" options into one "/DEFINE=
".-D
"s hidden in macro definitions (e.g. CFLAGS
).
-o
" option):
-o
" by "/OBJECT=
",
-o
" by "/EXECUTABLE=
".
libXXX.a
" by "XXX.olb
",
ar rc
" (or similar) by "LIBRARY /REPLACE
",
ranlib
",
$(LIB) : $(OBJS)
" can be
replaced by "$(LIB) : $(LIB)($(OBJS))
" without any further action lines
(other than "@ CONTINUE
", for MMS).
libXXX.a
" by "XXX.olb
",
-lXXX
" by "XXX.olb/LIBRARY
",
eventually supplying the path (in Unix, this is done by "-Lpath
" options,
which must be deleted).
/NAMES=AS_IS
" when there
are external data identifiers in the C source that only differ in case. But this must then
be done for all source files, or else the linker will not be able to resolve external names
(as it normally uppercases global symbols).
cd
" by "set default
"),
RUN
, or "MCR []
" (if the call has arguments).
install
*" targets (besides
commenting them out), as these typically involve lots of Unixisms. One has
to get an idea, though, of what is intended, and perhaps write a DCL procedure
to achieve similar goals.
binval
),
date = f$fao("!%D",f$cvui(32,32,f$fao("!AD",8,binval)))gets you the date. The
!AD
control string argument is undocumented.
binary_time[ 0,32] = %xA4FE0000 ! low longword of binary date binary_time[32,32] = %x0099D8C4 ! high longword date_string = - f$cvtime(f$fao("!%D",f$cvui(32,32,f$fao("!AD",8,binary_time))),"ABSOLUTE")
$ now_time = F$time() $ hrs = F$cvtime(now_time,, "hour") $ min = F$cvtime(now_time,, "minute") $ sec = F$cvtime(now_time,, "second") $ hun = F$cvtime(now_time,, "hundredth") $ $ ! $ ! Get a good seed to start the madness. $ ! $ seed = 360000 * hrs + 6000 * min + 100 * sec + hun $ seed = seed .and. %XFFFF $ $ highval = 100 ! Get a number from 0 to 100. $ gosub _RANDOM ! Get the random $ write sys$output random $ $ exit $ $_RANDOM: $ seed = (seed * 69069 + 1) .and. %XFFFFFFFF $ rand = (seed / %X100) .and. %XFFFF $ t = rand / highval $ k = %XFFFF / highval $ if rand .gt. (k * highval) then goto _RANDOM $ random = rand - t * highval + 1 $ $ Return
here is a DCL version of the R.G. Tantzen algorithm [algorithm 199 of the Association for Computiong Machinery (ACM)] that convert gregorian date to julian day number and back. all is integer arithmetic and 32-bit integers. this algorithm is year-2000-proof, leap-year-proof, century-leap-year-proof and you can compute julian day with this algorithm back to the begining of the gregorian calendar, october 15, 1582.
To compute the julian day number from d/m/y:
$ if m .gt. 2 $ then $ m = m - 3 $ else $ m = m + 9 $ y = y - 1 $ endif $ $ c = y / 100 $ y = y - 100*c $ $ j = c*146097/4 + y*1461/4 + (m*153 + 2)/5 + d + 1721119To compute d/m/y from the julian day number:
$ j = j - 1721119 $ $ y = (4*j - 1)/146097 $ j = (4*j - 1)-146097*y $ d = j/4 $ $ j = (4*d + 3)/1461 $ d = (4*d + 3)-1461*j $ d = (d+4)/4 $ $ m = (5*d - 3)/153 $ d = (5*d - 3)-153*m $ d = (d+5)/5 $ $ y = y*100 + j $ $ if m .lt. 10 $ then $ m = m + 3 $ else $ m = m - 9 $ y = y + 1 $ endif
/DEBUG
qualifier. Judging
from posts to comp.os.vms, this will not work on Itanium-based systems.
[posted to comp.os.vms by Hein RMS van den Heuvel (vandenheuvel@eps.enet.dec.com) on 21-NOV-1995]
$ if p1.eqs."" then $inquire p1 "image file name" $ open/read/write file 'f$parse(p1,".exe") $ offset = 80 !Alpha. We'll assume exe matches current system. $ if f$getsyi("arch_name").eqs."VAX" then offset = 32 $ read file header $ old_state = "OFF" $ new_state = "OFF" $ old_bit = f$cvsi(offset*8,1,header) $ new_bit = 0 $ if old_bit then old_state = "ON" $ if p2.eqs."" then p2 = .not.old_bit $ if p2 then new_bit = 1 $ if p2 then new_state = "ON" $ header[offset*8,1] = new_bit $ write/update/symbol file header $ close file $ write sys$output "Debug bit was ", old_state, ". Now ", new_state, "."
> Use f$string: > > $ job_time = f$cvtim("today+''f$string(32-f$cvtim("today+31-0",,"day"))'-0","absolute","date")Following up to Paddy's post indirectly since I haven't seen the original yet.
As Dave notes, this code would appear to fail on August 31, March 31, May 31, October 31 and January 29-31 when the +31 goes clear through the next month. It could be patched as:
$ job_time = f$cvtime("1-+"+f$string(32-f$cvtim("1-+31-",,"day"))+"-","absolute","date")I do like the algorithm. But even the patched DCL implementation suffers from a tiny race condition. If you execute the at midnight on the last day of a month the two invocations of f$cvtime might execute in two different months with surprising results.
The following uses a slightly different algorithm and avoids that race condition.
$ job_time = "1"+f$extract(1,9,F$CVTIME(F$CVTIME("1-","ABSOLUTE")+"+31-","ABSOLUTE"))Algorithm:
Start with the first of this month -- f$cvtime("1-","ABSOLUTE")
Add 31 days to get a date/time early next month -- f$CVTIME(x+"31-","ABSOLUTE")
Strip to just the month/year -- f$extract(1,9,y)
And make the day number "1". -- "1" + z
Many other people have already answered this question, but here's my solution for a one-"liner" (that is one command, though it's split across two text lines):
$ FirstOfNextMonth = "1-" + (f$cvtime("28--+4-","absolute","date") - "1-"-"2-"-"3-"-"4-")There are TWO hyphens and a plus sign following the 28. You may get away with only one hyphen there, but the proper syntax for an absolute date requires two hyphens to specify a date in the current month and year.
So here's how to compute the last date of the current month:
$ LastOfNextMonth = f$cvtime( "1-" + (f$cvtime("28--+4-","absolute","date") -"1-"-"2-"-"3-"-"4-") + "-1-","absolute","date")
$ base_date = F$CvTime("1--+31-","ABSOLUTE","DATE") $ first_day_of_next_month = "1-" + - F$CvTime(base_date,"ABSOLUTE","MONTH") + "-" + - F$CvTime(base_date,"ABSOLUTE","YEAR") $ last_day_of_this_month = - F$CvTime("''first_day_of_next_month'-1-","ABSOLUTE","DATE")
F$VERIFY()
$ SET NOVERIFY
to
$ SAVE_VERIFY = 'F$VERIFY(0)'The use of apostrophes causes F$VERIFY(0) to be executed before this command is interpreted (and be shown, should Verify have been on).
$ EXIT $STATUS + (0 * F$VERIFY(SAVE_VERIFY))
SYS$MANAGER:SYLOGICALS.COM
, this:
$ DEFINE/SYSTEM SYLOGIN_VERIFY 0and replace the
'F$VERIFY(0)'
with
'F$VERIFY(F$INTEGER(F$TRNLNM("SYLOGIN_VERIFY")))' [2]Then you can turn initial verification on and off by defining the logical name. (You can even turn on initial verification for a particular UIC group with something like
$ DEFINE/TABLE=LNM$GROUP_000345 SYLOGIN_VERIFY 1
.)
[2] Another neat trick circumvents the possibility of the logical name not being defined:
'F$VERIFY(F$INTEGER("0"+F$TRNLNM("SYLOGIN_VERIFY")))'
The following will return the previous procedure file spec in a DCL symbol called PREVIOUS_PROCEDURE.
;++ ; Copyright © 1993 - 1998 by Brian Schenkenberger and TMESIS. ; ALL RIGHTS RESERVED. ; Notice of Disclaimer ; ------------------------- ; ; This Software is provided "AS IS" and is supplied for informational purpose ; only. No warranty is expressed or implied and no liability can be accepted ; for any direct, indirect or consequential damages or for any damage whatso- ; ever resulting in the loss of systems, data or profit from the use of this ; software or from any of the information contained herein. The author makes ; no claims as to the suitablility or fitness of this Software or information ; contain herein for any particular purpose. ; ; ------------------------- ; NO TITLE TO AND/OR OWNERSHIP OF THIS SOFTWARE IS HEREBY TRANSFERRED. ANY ; MODIFICATION WITHOUT THE PRIOR WRITTEN CONSENT OF THE COPYRIGHT HOLDER IS ; PROHIBITED. ANY USE, IN WHOLE OR PART, OF THIS SOFTWARE FOR A COMMERCIAL ; PRODUCT WITHOUT THE PRIOR WRITTEN CONSENT OF THE COPYRIGHT HOLDER IS ALSO ; PROHIBITED. THE TECHNIQUES EMPLOYED IN THE SOFTWARE ARE THE INTELLECTUAL ; PROPERTY OF THE COPYRIGHT HOLDER. ;-- ;++ .SBTTL Determine the target architecture ;-- .NTYPE ...ON_ALPHA...,R31 .IIF EQ,<...ON_ALPHA...@-4&^XF>-5, ALPHA=0 .IIF DF,ALPHA, .DISABLE FLAGGING ;++ .SBTTL Primitive program datum definitions ;-- ZERO = 0 ; |_ BYTE = 1@0 ; |_|_ WORD = 1@1 ; |___|___ LONG = 1@2 ; |_______|_______ QUAD = 1@3 ; |_______________|_______________ OCTA = 1@4 ; |_______________|_______________| PAGE = 1@9 ; VAX page ; Alpha Pagelet BLOCK= 1@9 ; Standard disk block size ;++ ; The following macro is used to check the return status of system calls. ; It can take up to three arguments: ; STS ...... register or memory containing the status value ; ERROR .... instruction to execute if an error is detected ; NORMAL ... change status to a success before taking ERROR ;-- .MACRO CHKSTS,STS=To build it:,NORMAL= ,ERROR= ,?LBL .IIF DIF, , , MOVZWL STS,R0 .IIF IDN, , , BLBS R0,LBL .IIF DIF, , , BBSS #0,R0,LBL .IRP ERR, .SHOW MEB ERR .NOSHOW MEB .ENDR LBL: .ENDM CHKSTS .LIBRARY "SYS$LIBRARY:STARLET.MLB" ; look here for: $DSCDEF $SSDEF .PSECT DATA,WRT,NOEXE,5 PREV_PROC: .ASCID /PREVIOUS_PROCEDURE/ .ALIGN QUAD FILENAME_DSC: .LONG >!- >!0 .ADDRESS FILENAME_STR FILENAME_STR: .BYTE ^a" "[255] .PSECT CODE,NOWRT,EXE,5 .ENTRY GO,0 $CMEXEC_S - routin = GET_IDF_FILENAME CHKSTS PUSHAL #LIB$K_CLI_LOCAL_SYM PUSHAQ FILENAME_DSC PUSHAQ PREV_PROC CALLS #3,G^LIB$SET_SYMBOL CHKSTS RET .ENTRY GET_IDF_FILENAME,^m MOVAB G^EXE$SIGTORET,(FP) ; return signalled errors MOVAB @#CTL$AG_CLIDATA,R1 ; get address of the PPD MOVL PPD$L_PRC(R1),R1 ; adr of CLI own storage MOVL PRC_L_IDFLNK(R1),R1 ; get adr of IDF listhead MOVL IDF_L_LNK(R1),R0 ; get next IDF in queue BEQL 10$ ; there is none! at top! MOVL R0,R1 ; update IDF block pointer 10$: MOVL IDF_L_FILENAME(R1),R1 ; get the filename (ASCIC) MOVZBL (R1)+,R0 ; get filename's length MOVW R0,FILENAME_DSC ; store it in descriptor MOVC3 R0,(R1),FILENAME_STR ; copy name to descriptor MOVL #SS$_NORMAL,R0 ; say things went normal RET .END GO
$ MACRO PREV_PROC
$ LINK PREV_PROC,SYS$SYSTEM:SYS.STB,DCLDEF.STB
$ LINK PREV_PROC/SYSEXE,SYS$LOADABLE_IMAGES:DCLDEF.STB
$ numchar = 20 ! length of password to be generated $ password == "" ! holds the resulting password $ $ pstr = "$_abcdefghijklmnopqrstuvwxyz0123456789zyxwvutsrqponmlkjihgfedcba" $ time = f$time() - "-" - "-" - " " - ":" - ":" - "." $ tstr = f$extract(10,4,time) + - f$extract( 0,1,time) + - f$extract( 0,2,f$string(f$getjpi("","cputim"))) + - f$extract(15,2,time) $ seed = "" $ seed[0,32] = f$integer(tstr) $ seed = seed+seed+seed+seed $ startbit = 0 $ numbits = 5 $ pass_loop: $ currentchar = f$cvui(startbit,numbits+1,seed) $ password == password + f$extract(currentchar,1,pstr) $ startbit = startbit + numbits $ numchar = numchar - 1 $ if numchar .gt. 0 then goto pass_loop
To get the elapsed time from a lexical function:
I don't know where this trick came from, but I learned it from Jack Harvey.
$ start_time = f$cvtime ("",, "time") $ write sys$output "This is the start ... ''start_time'" $ wait 00:00:10 $ write sys$output "This is the elapsed time : " - + f$cvtime ("-''start_time'",, "time")
DIRECTORY
by modification date
$ ASSIGN LIB$DATE_FORMAT_037,- LIB$TIME_FORMAT_001 - LIB$DT_FORMAT/USER_MODE $ directx - ! Ignore any DIR symbols /date=modified- /width=(file:80,display:132)- /out=out.txt $ sort out.txt - /key=(pos:83,siz:22) tt:should do it as long as someone with privileges did the
@SYS$STARTUP:LIB$DT_STARTUP
first.
To get the /LOG value from within a batch job, use
$ junk = f$getqui("cancel_operation") $ job_log_null = f$getqui("display_job","job_log_null",,"this_job") $ job_name = f$getqui("display_job","job_name",,"this_job") $ log_specification = f$getqui("display_job","log_specification",,"this_job") $ mylog = "" $ if .not. job_log_null then - mylog = f$parse(log_specification,job_name,"sys$login:.log")Notice, however, that job_name doesn't include the version number, If there are multiple jobs with the same name, you can't get the information which version of the log file is the correct one.
To get the next available UIC, given the group number:
$!+ OPS_NEXT_UIC.COM $! $!! PURPOSE: To find the next available UIC. $! $ _GROUP_NUMBER = P1 $ N = -1 $_LOOP: $ N = N + 1 $ _MEMBER_NUMBER = F$FAO("!OW",N) $ UIC_INT = (%O'_MEMBER_NUMBER' + (%X10000 * %O'_GROUP_NUMBER')) $ UIC_NAME = F$IDENTIFIER(UIC_INT,"NUMBER_TO_NAME") $ IF (UIC_NAME .NES. "") THEN $ GOTO _LOOP $ UIC = F$FAO("!%U",UIC_INT) $ WRITE SYS$OUTPUT "The next available UIC is ''UIC'." $ EXITThis works if every UIC has a rights identifier coupled with it.
To validate a date of format dd-mm-yyyy (e.g. 30-10-2007), assuming your date string is in symbol p1:
$ PIPE date=F$CVTIME(F$ELEMENT(0,"-",p1)+"-"+- F$ELEMENT(F$INTEGER(F$ELEMENT(1,"-",p1)),"/",- "/JAN/FEB/MAR/APR/MAY/JUN/JUL/AUG/SEP/OCT/NOV/DEC/")+"-"+- F$ELEMENT(2,"-",p1),"ABSOLUTE") >nl: 2>nl: $ WRITE SYS$OUTPUT $STATUS $ SHOW SYMBOL dateA valid date will be converted into VMS absolute format as symbol "date" and $STATUS will be successful (odd).
$ pid = P1 ! PID for which process existance is to be tested $ PIPE newpid = F$GETJPI(F$FAO("!8XL",F$INTEGER("%X''pid'")),"PID") >NL: 2>NL: $ ProcessExists = $STATUS .AND. F$INTEGER("%X''newpid'").EQ.F$INTEGER("%X''pid'")
Here is an DCL aided leap-year test:
IF F$CVTIME("1-MAR-''year' -1-",,"DAY") ... ! Leap year?Remember Odd is True! 28 is not.
Using pure DCL, a mailbox can be opened (e.g. for inter-process communication). Though later versions of OpenVMS have the command CREATE/MAILBOX, this will work in older versions also (as far back as 1993er versions). This uses the fact that a termination mailbox is set up for a subprocess with a reproducable logical name (that isn't documented, AFAIK). When the subprocess exits the mailbox still has a connection so it doesn't get closed.
$ IF p1 .eqs. "SUB" $ THEN $ DEFINE/JOB/NOLOG sub_pid_'p2' 'F$GETJPI(0,"PID")' $ ATTACH/IDENT='p2' $ EXIT $ ELSE $ my_pid = F$GETJPI(0,"PID") $ SPAWN/NOLOG/NOLOGICAL/NOSYMBOL @'F$PARSE(F$ENVIRONMENT("PROCEDURE"),,,,"NO_CONCEAL")' "SUB" 'my_pid' $ mailbox_name = "sub_pid_''my_pid'" $ OPEN/READ/WRITE/SHARE mailbox DCL$ATTACH_'F$TRNLNM(mailbox_name)' $ ATTACH/IDENT='F$TRNLNM(mailbox_name)' $ DEASIGN/JOB DCL$ATTACH_'F$TRNLNM(mailbox_name)' $ DEASIGN/JOB 'mailbox_name' $ ENDIFAfter executing this snippet, there's an open filehandle named MAILBOX.
DEC C Run-Time Library Utilities Reference Manual
DEC Text Processing Utility Reference Manual
Digital Portable Mathematics Library
Extensible Versatile Editor Reference Manual
Guide to I/O User's Reference
Guide to Creating OpenVMS Modular Procedures
Guide to DECthreads
Guide to OpenVMS File Applications
OpenVMS Alpha Guide to 64-Bit Addressing and VLM Features
OpenVMS Alpha Guide to Upgrading Privileged-Code Applications
OpenVMS Alpha System Analysis Tool Manual
OpenVMS Calling Standard
OpenVMS Connectivity Developer Guide
OpenVMS Command Definition, Librarian, and Message Utilities Manual
OpenVMS Delta/XDelta Debugger Manual
OpenVMS Debugger Manual
OpenVMS Guide to Extended File Specifications
OpenVMS Linker Utility Manual
OpenVMS Programming Interfaces: Calling a System Routine
OpenVMS Programming Concepts
OpenVMS Record Management Services
OpenVMS Record Management Utilities Reference Manual
OpenVMS RTL General Purpose (OTS$) Manual
OpenVMS RTL Library (LIB$) Manual
OpenVMS RTL String Manipulation (STR$) Manual
OpenVMS RTL Screen Management (SMG$) Manual
OpenVMS System Services Reference Manual
OpenVMS Utility Routines Manual
OpenVMS VAX System Dump Analyzer Utility Manual
OpenVMS VAX RTL Mathematics (MTH$) Manual
POLYCENTER Software Installation Utility Developer's Guide
Porting VAX MACRO Code to OpenVMS Alpha
VAX MACRO and Instruction Set Reference Manual
Documentation for the current OpenVMS version (V7.3 at the time of writing)
as well as a few versions back is available online at
http://www.openvms.compaq.com/doc/.
Can I have an example of calling...?
How do I get the arguments from the command line?
How do I get a formatted error message in a variable?
How do I link against SYS$SYSTEM:SYS.STB on an Alpha system?
How do I do a SET DEFAULT from inside a program?
How do I turn my Fortran COMMON into a shareable image on Alpha?
How do I convert between IEEE and VAX floating data?
How do I get the argument count in a Fortran routine?
How do I get a unique system ID for licensing purposes?
What is an executable, shareable, system or UWSS image?
How do I do a file copy from a program?
What is a descriptor?
How many bytes are in a disk block?
How many bytes are in a memory page?
How do I create a process under another username?
Why do lib$spawn, lib$set_symbol fail in detached processes?
Where can I obtain Bliss, and the libraries and supporting files?
How can I open a file for shared access?
How can I have common sources for messages, constants?
How do I activate the OpenVMS Debugger from an application?
Dealing with Endian-ness?
How to resolve LINK-I-DATMISCH errors?
VAX C and DEC C, and other OpenVMS C Programming Considerations?
Status of Programming Tools on OpenVMS VAX?
The OpenVMS FAQ is archived in (at least) the following locations:
The CD is packaged with the OpenVMS distribution; its contents is available
online at
http://www.digiater.nl/openvms/freeware/.