OpenVMS Programming FAQ

This document will some day hopefully evolve into an OpenVMS Programming
FAQ. It is now and will then be maintained by Martin Vorländer. At the
moment, it's merely a collection of the VMS programming experience I and
others have gathered. The original version of this document is situated at
http://www.pdv-systeme.de/users/martinv/VMS_Programming_FAQ.html.

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, please tell me.

                   --------------------------------------

Disclaimer: I take no responsibility for the accuracy of any information in
this document.

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 "Compaq" instead of "DEC" or "Digital".

DEC, Digital, Compaq and/or other Compaq products referenced herein are
either trademarks or registered trademarks of Compaq. 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 Aug 17
05:51:50 2001.
---------------------------------------------------------------------------

Table of contents

1. General Information
1.1. I can't afford to buy licenses
1.2. What languages are available? Which are free?
1.3. What programming tools are there?
1.4. Run Time Libraries
1.5. The system API
1.6. The Calling Standard
1.7. Condition Values and System Messages
1.8. What is a descriptor?
1.9. What is an IO status block?
1.10. What is an item list?

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 FORTRAN
2.2.1. Where are the system header files for FORTRAN?
2.2.2. The Calling Standard in FORTRAN
2.3. Programming in Pascal
2.3.1. Where are the system header files for Pascal?
2.3.2. The Calling Standard in Pascal
2.4. Programming in BASIC
2.4.1. Where are the system header files for BASIC?
2.4.2. The Calling Standard in BASIC
2.5. Programming in BLISS
2.5.1. Where are the system header files for BLISS?
2.5.2. The Calling Standard in BLISS
2.5.3. Compiler can't find SYS$LIBRARY:STARLET.L32
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?
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?

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

6. Resources
6.1. OpenVMS Programming Documentation
6.2. OpenVMS FAQ
6.3. DJE VMS mentor pages
6.4. Arne Vajhøj's pages
6.5. OpenVMS Freeware CD

7. Credits

---------------------------------------------------------------------------

1. General Information

This section deals with some fundamental topics.

1.1. I can't afford to buy licenses

There exists an OpenVMS hobbyist program by which one can get licenses for
OpenVMS and a lot of layered products for non-commercial use, see
http://www.montagar.com/hobbyist/.
                   --------------------------------------

1.2. What languages are available? Which are free?

   * Compiler languages
        o commercial (license required - see "I can't afford to buy
          licenses")
             + DEC Ada
             + DEC BASIC (replaced VAX BASIC)
             + DEC C (replaced VAX C)
             + DEC C++
             + DEC COBOL (replaced VAX COBOL)
             + VAX DIBOL
             + DEC FORTRAN
             + DEC Pascal (replaced VAX Pascal)
             + DEC PL/I (replaced VAX PL/I)
        o free / supplied with OpenVMS
             + GCC (was available e.g. from www.progis.de)
             + VAX BLISS-32 / Alpha BLISS (on the OpenVMS Freeware CD)
             + VAX MACRO / Alpha MACRO-32
             + Alpha MACRO-64 (on the OpenVMS Freeware CD)
   * Interpreters
        o commercial (license required - see "I can't afford to buy
          licenses")
             + VAX APL
        o free / supplied with OpenVMS
             + Perl (available in source from CPAN; pre-built binaries from
               www.sidhe.org; also on the OpenVMS Freeware CD or as a
               Compaq supported product from
               http://www.openvms.compaq.com/openvms/products/ips/apache/csws.html
               - though not the latest version)
             + DCL (DIGITAL Command Language - the VMS "shell" language)

                   --------------------------------------

1.3. What programming tools are there?

See "I can't afford to buy licenses" for the commercial products mentioned.

   * OpenVMS debugger (comes with VMS; command line and DECwindows
     interface)
     Tips and tricks are in the section "How do I...debug an application?"
   * Module Management System (MMS)
     This is a cousin of what is called make under Unix. Some caveats
     apply, though (some of them are described in the section "Converting a
     Unix Makefile to a DESCRIP.MMS")
     Free alternatives:
        o MadGoat Make Utility (MMK; an MMS clone, available e.g. from
          www.madgoat.com)
        o GNU make
   * Code Management System (CMS)
     Free Alternatives:
        o Resource Control System (RCS)
   * Performance and Coverage Analyzer (PCA)
     A profiler tool
   * Source Code Analyzer (SCA)
     A cross-reference tool, best used with LSE
   * Language Sensitive Editor (LSE)
     Built on top of TPU/EVE
     Free Alternatives:
        o GNU Emacs
   * Test Manager
   * DECset (nee VAXset)
     This consists of MMS, CMS, PCA, SCA, LSE, and Test Manager.
   * GNU diff and patch (available e.g. from http://www.crinoid.com/utils/)

Also see the section "How do I ...create a program source file?" for
available editors.
                   --------------------------------------

1.4. Run Time Libraries

Run-time libraries (at least for DEC languages) come with the operating
system! Exceptions to this rule are

   * DEC C v5.6 or later, which gives the possibility to use most of the
     VMS v7 C runtime library under VMS v6 (except the functions related to
     timezones).
     See "How to use the VMS v7 C RTL under VMS v6".
   * The DEC C "Backport Library" AACRTL060, which can be used to install
     VMS v6 C programs under VMS v5.5 (where the DEC C RTL isn't included).

                   --------------------------------------

1.5. The system API

   * System services are described as $service, but mostly must be called
     from High Level Languages as SYS$service.
   * System libraries include:
     LIB$
          general purpose; many wrapping system services, e.g. to avoid use
          of item lists when only dealing with one item
     SMG$
          screen management
     STR$
          string manipulation
     MTH$
          math
     OTS$
          general purpose
     SOR$
          sorting
     DCX$
          compression
     CLI$
          interface to DCL's parameter parsing
     LBR$
          interface to the VMS librarian
     TPU$
          interface to the Text Processing Utility (TPU)
     FDL$
          interface to the File Definition Language (FDL)
     PSM$
          interface to the Print Symbiont Modification (PSM) Utility
     NCS$
          interface to the National Character Set (NCS) Utility
     LGI$
          interface to LOGINOUT
     CONV$
          interface to the CONVERT utility
     MAIL$
          interface to the MAIL utility
   * Online help can be obtained through $HELP System_Services and $HELP
     RTL_Routines.
   * All manual/help entries follow the description scheme
     Format
          shows the parameters; optional ones in [] (these are almost
          always passed by reference; pass 0 to leave them out)
     Returns
          describes the value returned by the function
     Arguments
          describes the parameters in detail (see below)
     Description
          describes what the service does
     Condition Values Returned
          if the return value is a condition code (there are few functions
          for which it isn't), lists the possible ones
          See "Condition Values and System Messages".
     Example
          gives an example of usage
   * Argument descriptions in detail contain:
        o OpenVMS usage
          This describes
             + how the parameter contents is to be interpreted, e.g.
               cond_value, address, mask_longword
             + or the structure of the parameter, e.g. item_list_3,
               vector_longword_unsigned, io_status_block
             + or duplicates type information
             + or says nothing at all: unspecified
        o type
          type/length of the parameter (or of the base type if structured
          parameter):
             + byte/word/longword/quadword [integer] (signed / unsigned)
             + address
             + floating (including the floating type: F,G,H,...)
             + character string / character-coded text string
             + procedure value
             + unspecified
        o access
          describes how the routine accesses the parameter:
             + read only
             + write only
             + modify / read-write
             + function call (before return)
             + call without stack unwinding
        o mechanism
             + by value
               also called an immediate parameter; the parameter is the
               argument itself (at most 32 bit on VAX, 64 bit on Alpha;
               longer items must be passed by reference)
             + by reference
               the parameter is the address of the argument
             + by descriptor
               the parameter is the address of a descriptor structure
               see the section "What is a descriptor?"

                   --------------------------------------

1.6. The Calling Standard

Calling functions that are written in one language from another languages
is easy, as long as all adhere to a concept called the "Calling Standard".
This is a set of conventions on how to pass parameters.

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 C", "The Calling Standard
in Pascal", and "The Calling Standard in BLISS".
                   --------------------------------------

1.7. Condition Values and System Messages

A condition value is a longword returned by many system services and system
library routines. It is coded as follows:

   * bits 0-2 : severity
     0
          warning
     1
          success
     2
          error
     3
          informational
     4
          severe (fatal) error
     5-7
          (reserved)
   * bits 3-15 : message number
   * bits 16-27 : facility number
   * bits 28-31 : control flags
     bit 28
          inhibit message output

(bit 0 is the LSB, bit 31 the MSB). This means that all odd condition
values signal success, while even ones mean trouble of varying degree.

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.).

As the severity and/or facility could vary, a returned condition code calue
should not be compared for equality to some constant, but checked against a
message number using the LIB$MATCH_COND routine.

All system messages 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.
                   --------------------------------------

1.8. What is a descriptor?

[Taken from PROG13 of the OpenVMS FAQ]

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.

[...]

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 [see "OpenVMS
Programming Documentation"].

[Steve Hoffman]

For C, the various descriptor types are declared in DESCRIP.H.

Also see the section about "The Calling Standard".
                   --------------------------------------

1.9. What is an IO status block?

{TBS}
                   --------------------------------------

1.10. What is an item list?

{TBS}
                   --------------------------------------

2. Language Specifics

This section discusses language specific issues.

2.1. Programming in C

2.1.1. Where are the system header files for C?

For VAX C, they are in 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.
                   --------------------------------------

2.1.2. The Calling Standard in C

   * Passing mechanisms:
     by value
          just pass the value
     by reference
          pass a pointer to the value
     by reference, array reference
          {TBS}
     by descriptor
          as C offers no support for descriptors, one has to construct the
          descriptor by hand, and pass a pointer to it. <descrip.h> has
          types and macros to deal with descriptors.
     by descriptor - fixed length string descriptor
          this is just a special descriptor type: dsc$descriptor_s

                   --------------------------------------

2.1.3. VAX C and DEC C, and other C Programming Considerations

[posted to comp.os.vms by Hoff (Stephen) Hoffman
(hoffman@xdelta.zko.dec.com) on 9-FEB-1999]

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 Digital C compiler for OpenVMS VAX
systems. DEC C is the Digital 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. DEC C is an ANSI C compiler, and can also compile
most VAX C code when /STANDARD=VAXC is specified.

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. In 1998, the C compiler
version is DEC C V5.7.

The system manager can choose the system default C compiler when DEC 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 DEC C on the same
OpenVMS VAX system.

Various DEC C versions can be installed on OpenVMS VAX V5.5-2 and later.
OpenVMS releases such as V5.5-2 and V6.0 will require the installation of a
DEC C RTL kit, a kit that is included with the DEC C compiler. Versions
V6.1 and later do not require a seperate RTL kit, but DEC C RTL ECO kits
are available to resolve problems found with the C RTL on various OpenVMS
releases.

With DEC 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=(...)).

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.

Versions of DEC C such as V5.7 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 DEC C versions such as V5.7, 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.)

Example C code is available in SYS$EXAMPLES:, in DECW$EXAMPLES: (when the
DECwindows examples are installed), in UCX$EXAMPLES: (when Digital TCP/IP
is installed), and on the OpenVMS Freeware CD-ROMs.
                   --------------------------------------

2.1.4. How to get prototypes for system services

With DEC C v5.6 and later, defining the macro __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).
                   --------------------------------------

2.1.5. How to use the VMS v7 C RTL under VMS v6

The VMS v7 C RTL offers a lot more Unix functionality than previous
versions. This can make porting Unix applications easier, if not possible
at all. Under VMS v6, when using DEC C v5.6 or later, one can link against
a static version of the VMS v7 C RTL by defining

  $ define decc$crtlmap sys$library:decc$crtl.exe
  $ define lnk$library  sys$library:decc$crtl.olb

It becomes necessary to use this functionality when the declaration of
functions in the header files is conditionalized by

  #if __CRTL_VER >= 70000000
    ...
  #endif

However, 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.
                   --------------------------------------

2.1.6. Traps and Pitfalls in C

   * The $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*.
     Another incarnation of this pitfall: If you use the following
     construct

           void sub(char str[])
           {
              $DESCRIPTOR(str_dsc, str);
              ...


     str_dsc.dsc$w_length is 3 (== sizeof(char*)-1), and not sizeof(str)-1.

                   --------------------------------------

2.2. Programming in FORTRAN

2.2.1. Where are the system header files for FORTRAN?

{TBS}
                   --------------------------------------

2.2.2. The Calling Standard in FORTRAN

{TBS}
                   --------------------------------------

2.3. Programming in Pascal

2.3.1. Where are the system header files for Pascal?

{TBS}
                   --------------------------------------

2.3.2. The Calling Standard in Pascal

{TBS}
                   --------------------------------------

2.4. Programming in BASIC

2.4.1. Where are the system header files for BASIC?

{TBS}
                   --------------------------------------

2.4.2. The Calling Standard in BASIC

{TBS}
                   --------------------------------------

2.5. Programming in BLISS

2.5.1. Where are the system header files for BLISS?

{TBS}
                   --------------------------------------

2.5.2. The Calling Standard in BLISS

{TBS}
                   --------------------------------------

2.5.3. Compiler can't find SYS$LIBRARY:STARLET.L32

Problem: After installation of BLISS on an Alpha system, compiling BLISS
programs fails with

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.)
                   --------------------------------------

2.6. Programming in MACRO

2.6.1. Where are the system header files for MACRO?

{TBS}
                   --------------------------------------

2.6.2. The Calling Standard in MACRO

{TBS}
                   --------------------------------------

3. How Do I ...?

3.1. ...create a program source file?

Editors available:

   * with OpenVMS:
        o TECO
        o EDT
        o Extensible Versatile Editor (EVE; built upon TPU)
        o Language Sensitive Editor (LSE; built upon TPU, part of DECset)
   * free:
        o ED (EDT compatible; also for DOS & Unix; from ftp.wku.edu)
        o EMACS (19.28; no current version that I know of)
        o MicroEMACS (e.g. from ftp://ftp.pdv-systeme.de/vms/)
        o vim (e.g. from www.polarfox.com)
        o ...

                   --------------------------------------

3.2. ...compile a program source file?

{TBS}
                   --------------------------------------

3.3. ...link a program?

{TBS}
                   --------------------------------------

3.4. ...link against a shareable image?

{TBS}
                   --------------------------------------

3.5. ...build a shareable image?

See The Shareable Image Cookbook.
                   --------------------------------------

3.6. ...debug an application?

{TBS}
See also "How do I ...debug an application that uses the terminal?".
                   --------------------------------------

3.7. ...get F$EDIT functionality from a program?

[posted to comp.os.vms by Lennart Börjeson (lennartb@front.se) on
14-MAR-1996]

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

                   --------------------------------------

3.8. ...validate a user's password?

[adapted from a post to comp.os.vms by Carl J Lydick on 9-MAY-1996]

/*
** 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 */

                   --------------------------------------

3.9. ...debug an application that uses the terminal?

   * If you're using DECwindows:
     Either use the graphical debugger, or

           $ DEFINE DBG$DECW$DISPLAY " "  ! disable the debugger's DECwindows interface
           $ CREATE /TERMINAL /DETACHED /NOPROCESS /DEFINE_LOGICAL=DBGTERM
           $ ALLOCATE DBGTERM:
           $ DEFINE DBG$INPUT  DBGTERM:
           $ DEFINE DBG$OUTPUT DBGTERM:


   * If you have two LAT connections:
     On the debug-terminal-to-be (let that be _LTAx:):

           $ SET PROCESS /PRIVILEGE=(LOG_IO)
           $ SET TERMINAL /NOHANGUP /PERMANENT
           $ LOGOUT /NOHANGUP


     Alternatively: 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 /NOHANGUP


     suffices.

     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:


                   --------------------------------------

3.10. ...get info from the command line? Do I need to parse it myself?

See http://home.earthlink.net/~djesys/vms/freevms/mentor/dcl_cmd.html.
                   --------------------------------------

3.11. ...get the DCLTABLE verb a program was called by?

[posted to comp.os.vms by Joshua Cope (cope@star.enet.dec.com) on
5-NOV-1998]

Feeding the special label $VERB to the CLI$GET_VALUE routine gives you the
verb.
                   --------------------------------------

3.12. ...get info about the DECwindows display?

[posted to comp.os.vms by Stephen Hoffman (hoffman@xdelta.enet.dec.com) on
23-JUN-1995]

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.
                   --------------------------------------

3.13. ...program a deterministic automaton?

The system library has a routine to easily implement a table-driven finite
state parser. It's LIB$TPARSE for VAX, and LIB$TABLE_PARSE for Alpha.
Implementing the state table is easily done only from MACRO or BLISS.
                   --------------------------------------

4. Porting Software from Unix

4.1. Converting a Unix Makefile to a DESCRIP.MMS

Of course, these can only be rules-of-thumb. A Unix Makefile can (mostly
due to excessive use of Unixisms, e.g. shell scripting) be partly or
completely un-convertable.

   * Replace all ":" separating targets and prerequisites by "<blank>:"
     (because under VMS, ":" is a legal filespec character).
   * Find executable names and append ".exe".
     These typically are targets where the action line contains a "$(CC)"
     without "-c".
     (Watch out for "-c"s hidden in macros!)
   * Replace ".o" by ".obj".
   * Replace "$(MAKE)" by "$(MMS)". Or define a DCL symbol to equate MAKE
     to MMS.
   * Under Unix, $(CC) is used for both compiling and linking:
     Replace "$(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.
   * Replace the contents of the CC macro by something appropriate (e.g.
     "CC/DECC").
     Don't forget to "/PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES".
   * In a compile or link action, replace the separating blanks in the list
     by ",".
     Do this also for lists hidden in macros (typically "OBJS = a.o b.o
     c.o"). The VMS Linker can cope with blank-separated lists, though.
   * DEC's C compilers don't tolerate multiple "/DEFINE" qualifiers (or
     more accurately, it only uses the last "/DEFINE" qualifier), so one
     has to gather all "-D" options into one "/DEFINE=".
     Look out for "-D"s hidden in macro definitions (e.g. CFLAGS).
   * File specifications:
        o Replace Unix paths by their VMS counterparts,
        o If paths are sub-pathed, and part of the path is a macro,
          substitute the macro contents.
        o Actually, the C RTL handles Unix filespecs quite well. So, if a
          filespec is passed as a parameter (i.e. not DCL), simple
          double-quoting (to avoid clashes with qualifiers) may be enough.
   * Output files (Unix cc "-o" option):
        o If the file being built is an object file, replace "-o" by
          "/OBJECT=",
        o If the file being built is an exceutable, replace "-o" by
          "/EXECUTABLE=".
   * Bulding libraries:
        o Replace "libXXX.a" by "XXX.olb",
        o Replace "ar rc" (or similar) by "LIBRARY /REPLACE",
        o Remove calls to "ranlib",
        o Often a dependancy of the form "$(LIB) : $(OBJS)" can be replaced
          by "$(LIB) : $(LIB)($(OBJS))" without any further action lines
          (other than "@ CONTINUE", for MMS).
   * Using libraries:
        o Replace "libXXX.a" by "XXX.olb",
        o In link actions, replace "-lXXX" by "XXX.olb/LIBRARY", eventually
          supplying the path (in Unix, this is done by "-Lpath" options,
          which must be deleted).
   * It can help to specify the CC qualifier "/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).
   * Find program execution statements, and
        o substitute by the apropriate DCL command (e.g. "cd" by "set
          default"),
        o otherwise prepend them with RUN, or "MCR []" (if the call has
          arguments).
   * I usually don't touch "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.
   * Initialize all macros that are used; MMS, when not instructed
     otherwise, imports all DCL symbols as macros!

                   --------------------------------------

4.2. Libraries to Aid Porting

Out of the porting of the Apache webserver software came the OpenVMS
Porting Library.
For GUIs, Compaq has the GTK+ for OpenVMS Alpha package.
The OpenVMS Freeware CD has a number of libraries.
In the course of porting Samba to VMS, the FRONTPORT Porting Library. came
to life.
                   --------------------------------------

4.3. Links to Other Porting Resources

David Mathog's website has "Unix to OpenVMS Porting Notes" and "X11/Motif
portability concerns" .
There is a project on SourceForge called "GNU's not VMS" with the goal to
build a Unix environment on VMS.
                   --------------------------------------

5. DCL Tips & Tricks

In this section, we'll discuss a few tricks the DIGITAL Command Language
(DCL) has to offer.

5.1. Getting the date from a binary quadword value

   * If you e.g. read a VMS binary date value from a file (say, to 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.
   * [posted by Peter Weaver (pweaver@stelco.ca) to comp.os.vms on
     2-NOV-1999]

     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")

                   --------------------------------------

5.2. Producing a random number

[posted to comp.os.vms by brivan@spire.com (Brian VandeMerwe) on
17-AUG-1995]

$   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

                   --------------------------------------

5.3. Computing the julian day number

[posted to comp.os.vms by Pierre.Bru@spotimage.fr on 20-AUG-1998]

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 + 1721119

To 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

                   --------------------------------------

5.4. Toggling an image's debug bit

Sometimes it comes handy to switch off the debugger being called, even if
the image has been linked with the /DEBUG qualifier.

[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, "."

                   --------------------------------------

5.5. Computing the first and the last day of a month

   * [Posted to comp.os.vms by John Briggs (vaxs09@alpha.tst.tracor.com) on
     28-Sep-1999]

     > 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
   * [Posted to comp.os.vms by Dave Cantor (DCantor@shore.net) on
     1-Oct-1999]

     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")

                   --------------------------------------

5.6. Tricks with F$VERIFY()

[posted to comp.os.vms by Dave Cantor (DCantor@shore.net) on 4-NOV-1999]

  1. Change $ SET NOVERIFY to

          $ SAVE_VERIFY = 'F$VERIFY(0)'

     The use of apostrophes causes verify off before this command is
     interpreted.
  2. Change the exit (or insert at the end of the file)

          $  EXIT $STATUS + (0 * F$VERIFY(SAVE_VERIFY))

If you want to get fancy, in SYS$MANAGER:SYLOGICALS.COM, define this:

     $ DEFINE/SYSTEM   SYLOGIN_VERIFY  0

and 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")))'

                   --------------------------------------

5.7. Finding the name of the calling procedure

[posted to comp.os.vms by Brian Schenkenberger (VAXman@tmesis.com) on
27-JAN-2000]

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=,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

To build it: $ MACRO PREV_PROC
Link on VAX: $ LINK PREV_PROC,SYS$SYSTEM:SYS.STB,DCLDEF.STB
Link on Alpha: $ LINK PREV_PROC/SYSEXE,SYS$LOADABLE_IMAGES:DCLDEF.STB

                   --------------------------------------

5.8. Generating a password

[taken from DSN$STARTUP.COM, © Digital Equipment Corporation]
The following DCL snippet will generate a 20 character 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
$ password == ""
$ char = 0
$ pass_loop:
$   currentchar = f$cvui(startbit,numbits+1,seed)
$   password == password + f$extract(currentchar,1,pstr)
$   startbit = startbit + numbits
$   char = char + 1
$   if char .ne. 21 then goto pass_loop

                   --------------------------------------

6. Resources

6.1. OpenVMS Programming Documentation

Everything OpenVMS Programming is laid down in a subset of the OpenVMS full
documentation set, consisting of (as of OpenVMS/Alpha 6.2):

 Manual                                                       Order Number
 Creating an OpenVMS AXP Step 2 Device Driver from a Step 1
 Device Driver                                                AA-Q28TA-TE
 Creating an OpenVMS AXP Step 2 Device Driver from an OpenVMS
 VAX Device Driver                                            AA-Q28UA-TE
 DEC Text Processing Utility Reference Manual                 AA-PWCCA-TE
 Digital Portable Mathematics Library (DPML)                  AA-PV6VB-TE
 Guide to Creating OpenVMS Modular Procedures                 AA-PV6AA-TK
 Guide to the DEC Text Processing Utility                     AA-PWCBA-TE
 Guide to DECthreads                                          AA-Q39DA-TK
 Guide to OpenVMS File Applications                           AA-PV6PA-TK
 Migrating to an OpenVMS AXP System: Planning for Migration   AA-PV62A-TE
 Migrating to an OpenVMS AXP System: Recompiling and Relinking
 Applications                                                 AA-PV63A-TE
 Migrating to an OpenVMS AXP System: Porting VAX MACRO Code   AA-PV64A-TE
 OpenVMS AXP Device Support: Developer's Guide                AA-Q28SA-TE
 OpenVMS AXP Device Support: Reference                        AA-Q28PA-TE
 OpenVMS AXP System Dump Analyzer Utility Manual              AA-PV6UB-TE
 OpenVMS Calling Standard                                     AA-PV69B-TK
 OpenVMS Command Definition, Librarian, and Message Utilities
 Manual                                                       AA-PV6DA-TK
 OpenVMS Debugger Manual                                      AA-PV6BB-TK
 OpenVMS Delta/XDelta Debugger Manual                         AA-PWCAA-TE
 OpenVMS Linker Utility Manual                                AA-PV6CA-TK
 OpenVMS I/O User's Reference Manual                          AA-PV6SA-TK
 OpenVMS Programming Concepts Manual                          AA-PV67B-TK
 OpenVMS Programming Environment Manual                       AA-PV66B-TK
 OpenVMS Programming Interfaces: Calling a System Routine     AA-PV68A-TK
 OpenVMS Record Management Services Reference Manual          AA-PV6RA-TK
 OpenVMS Record Management Utilities Reference Manual         AA-PV6QA-TK
 OpenVMS RTL Screen Management (SMG$) Manual                  AA-PV6LA-TK
 OpenVMS RTL String Manipulation (STR$) Manual                AA-PV6MA-TK
 OpenVMS RTL Library (LIB$) Manual                            AA-PV6KB-TK
 OpenVMS RTL General Purpose (OTS$) Manual                    AA-PV6HA-TK
 OpenVMS RTL Parallel Processing (PPL$) Manual                AA-PV6JA-TK
 OpenVMS RTL Mathematics (MTH$) Manual                        AA-PVXJA-TE
 OpenVMS System Services Reference Manual: A-GETMSG           AA-PV6FB-TK
 OpenVMS System Services Reference Manual: GETQUI-Z           AA-PV6GB-TK
 OpenVMS Utility Routines Manual                              AA-PV6EB-TK
 OpenVMS VAX Device Support Manual                            AA-PWC8A-TE
 OpenVMS VAX Device Support Reference Manual                  AA-PWC9A-TE
 OpenVMS VAX System Dump Analyzer Utility Manual              AA-PV6TA-TE
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/.
                   --------------------------------------

6.2. OpenVMS FAQ

The OpenVMS FAQ has a section about Programming. The following topics are
discussed there (taken from the 10-Apr-2001 issue):

PROG1. How do I call <routine_name> from <language_name>?
PROG2. How do I get the arguments from the command line?
PROG3. How do I get a formatted error message in a variable?
PROG4. How do I link against SYS$SYSTEM:SYS.STB on an Alpha system?
PROG5. How do I do a SET DEFAULT from inside a program?
PROG6. How do I create a shareable image transfer vector on an Alpha
system?
PROG7. How do I turn my Fortran COMMON into a shareable image on Alpha?
PROG8. How do I convert between IEEE and VAX floating data?
PROG9. How do I get the argument count in a Fortran routine?
PROG10. How do I get a unique system ID for licensing purposes?
PROG11. What is an executable, shareable, system or UWSS image?
PROG12. How do I do a file copy from a program?
PROG13. What is a descriptor?
PROG14. How many bytes are in a disk block?
PROG15. How many bytes are in a memory page?
PROG16. How do I create a process under another username?
PROG17. Why do lib$spawn, lib$set_symbol fail in detached processes?
PROG18. Where can I obtain Bliss, and the libraries and supporting files?
PROG19. How can I open a file for shared access?
PROG20. How can I have common sources for messages, constants?
PROG21. How do I activate the OpenVMS Debugger from an application?

                   --------------------------------------

6.3. DJE VMS mentor pages

See DJE VMS mentor pages
                   --------------------------------------

6.4. Arne Vajhøj's pages

Arne Vajhøj has a lot of VMS programming examples at
ftp://ftp.hhs.dk/pub/vms/.
                   --------------------------------------

6.5. OpenVMS Freeware CD

Not exactly a resource for programming examples, the OpenVMS Freeware CD
contains lots of packages (most of them in source) that can be helpful in
the everyday use of VMS.

The CD is packaged with the OpenVMS distribution; its contents is available
online at www.openvms.compaq.com.
                   --------------------------------------

7. Credits

My warmest Thank You to

   * all the people that keep comp.os.vms alive with their helpful posts.
   * DEC for a stable, well designed operating system like OpenVMS.
   * my employer PDV-SYSTEME for letting me get in touch with VMS.

                   --------------------------------------

            Martin Vorländer - on the web - mv@pdv-systeme.de -
                         martin@radiogaga.harz.de