The VMS SharkOpenVMS Notes: Hacking Starlet Libraries

  1. The information and software presented on this web site are intended for educational use only by OpenVMS application developers and OpenVMS system attendants.
  2. The information and software presented on this web site are provided free of charge.
  3. The information and software presented on this web site are presented to you as-is. I will not be held responsible in any way if the information and software presented on this web site damages your computer system, business or organization (sounds like the legal warning from a Microsoft shrink-wrap seal, eh?)
  4. Is this text too small? You have two options:
    1. hold down the CTRL key while rolling the mouse wheel (zoom-in, zoom-out)
    2. use your keyboard like so:
      • hit: CTRL with "-" key to zoom smaller
      • hit: CTRL with "+" key to zoom larger
      • hit: CTRL with zero key to reset zoom

Overview

OpenVMS documentation is some of the best I've seen but nothing is 100% accurate which is why you need other options. If you write programs requiring OpenVMS system calls, then doing a simple hack of the Starlet library is one such option. The whole purpose of the next example is to produce a searchable text file of the BASIC definition for the Starlet system library (known as BASIC$STARLET.TLB) in order to "double check" passing mechanisms, variable types and variable sizes described in official OpenVMS documentation.

BTW, the following procedure requires ~ 7900 blocks for OpenVMS-8.3 so be careful.

Dumping a Library to a Text File

Legend: <ur> = user response
        <sr> = system response

<sr> $                                                    ! this is the default prompt
<ur> set def sys$library
<sr> $
<ur> dir *.tlb                                            ! see all TLB files
<sr> Directory SYS$COMMON:[SYSLIB]

     BASIC$STARLET.TLB;1 DECC$RTLDEF.TLB;1 EPC$FACILITY.TLB;1 ERFLIB.TLB;1
     LIB_ADA_SUBSET.TLB;1 NTA.TLB;1 STARLETSD.TLB;1
     STARLET_RECENT_ADA_SUBSET.TLB;1 SYS$LIB_C.TLB;1 SYS$STARLET_C.TLB;1
     TCPIP$TEMPLATES.TLB;1

     Total of 11 files.
     $
<ur> lib/list BASIC$STARLET.TLB/text                      ! see library chapters
<sr>
Directory of TEXT library SYS$COMMON:[SYSLIB]BASIC$STARLET.TLB;1 on 25-MAR-2012 09:18:11
Creation date:  12-AUG-2010 17:23:28      Creator:  Librarian A09-30
Revision date:  12-AUG-2010 17:23:30      Library format:   3.0
Number of modules:    318                 Max. key length:  39
Other entries:          0                 Preallocated index blocks:     31
Recoverable deleted blocks:        0      Total index blocks used:       15
Max. Number history records:      20      Library history records:        0
Library is in DCX data reduced format

$ACCDEF
$ACCESSDEF
$ACEDEF
$ACLDEF
$ACMEDEF
$ACMEMSGDEF
$ACMEVMSDEF
$ACRDEF
$AFRDEF
$AGNDEF
$ALPHADEF
$ARGDEF
$ARMDEF
$ATRDEF
$BASDEF
$BRKDEF
$CAPDEF
$CBODEF
$CHFDEF
$CHKPNTDEF
$CHPDEF
$CLIDEF
$CLIMSGDEF
$CLISERVDEF
$CLIVERBDEF
$CLSDEF
$CLUEVTDEF
$CMBDEF
$COBDEF
$CONVDEF
$CONVMSGDEF
$CPUIDEF
$CQUALDEF
$CRDEF
$CREDEF
$CRFDEF
$CRFMSG
$CSTDEF
$CVTDEF
$CVTFNMDEF
$CVTMSG
$DCDEF
$DDTMDEF
$DDTMMSGDEF
$DELPRCSYMDEF
$DEVDEF
$DIBDEF
$DIRENTDEF
$DMTDEF
$DPSDEF
$DSCDEF
$DSTDEF
$DTIDEF
$DTKDEF
$DTKMSG
$DVIDEF
$DVSDEF
$EEOMDEF
$EFNDEF
$EGPSDEF
$EGSDEF
$EGSTDEF
$EGSYDEF
$EIDCDEF
$EMHDEF
$ENVDEF
$EOBJRECDEF
$EOMDEF
$EOMWDEF
$EPMDEF
$EPMMDEF
$EPMVDEF
$EPMWDEF
$ERADEF
$ESDFDEF
$ESDFMDEF
$ESDFVDEF
$ESGPSDEF
$ESRFDEF
$ETIRDEF
$EVAX_INSTRDEF
$EVENTDEF
$FABDEF
$FALDEF
$FDLDEF
$FDLMSGDEF
$FIBDEF
$FIDDEF
$FLTDEF
$FMLDEF
$FORDEF
$FSCNDEF
$GEN64DEF
$GETSPIDEF
$GLOCKDEF
$GPSDEF
$GSDEF
$GSYDEF
$HLPDEF
$HWDEF
$IACDEF
$ICCDEF
$IDCDEF
$IEEEDEF
$ILEDEF
$INDICTDEF
$INITDEF
$IODEF
$IOSADEF
$IOSBDEF
$ISSDEF
$JBCMSGDEF
$JPIDEF
$JPIFDEF
$KGBDEF
$LADEF
$LATDEF
$LATMSGDEF
$LBRCTLTBL
$LBRDEF
$LCKDEF
$LDDEF
$LEPMDEF
$LGIDEF
$LHIDEF
$LIBCLIDEF
$LIBDCFDEF
$LIBDEF
$LIBDTDEF
$LIBFILDEF
$LIBFISDEF
$LIBVMDEF
$LIBWAITDEF
$LICENSEDEF
$LKIDEF
$LKSBDEF
$LMFDEF
$LNKDEF
$LNMDEF
$LOGTYPDEF
$LPDEF
$LPRODEF
$LSDFDEF
$LSRFDEF
$LSYDEF
$MACIDDEF
$MAILDEF
$MAILMSGDEF
$MAPPINGDEF
$MHDDEF
$MHDEF
$MMEMSGDEF
$MMIDEF
$MNTDEF
$MOUNDEF
$MSGDEF
$MSGHLPDEF
$MT2DEF
$MT3DEF
$MTADEF
$MTDEF
$MTHDEF
$NAMDEF
$NCSDEF
$NETDEF
$NSADEF
$NSAMSGDEF
$NSARECDEF
$OBJRECDEF
$OPCDEF
$OPCMSG
$OPRDEF
$OSSDEF
$OTSDEF
$PCCDEF
$PDSCDEF
$PMMDEF
$POSIX_SERVICEDEF
$POWERDEF
$PPLDEF
$PPROPDEF
$PQLDEF
$PRCDEF
$PRDEF
$PRODEF
$PROMDEF
$PROVDEF
$PROWDEF
$PRTDEF
$PRVDEF
$PRXDEF
$PSCANDEF
$PSIGDEF
$PSLDEF
$PSMMSGDEF
$PTDDEF
$QSRVDEF
$QUIDEF
$RABDEF
$RBLDDEF
$REGDEF
$REGMSG
$RMEDEF
$RMIDEF
$RMSDEF
$RNHBLKDEF
$RSDMDEF
$S2DGBDEF
$SBKDEF
$SCRDEF
$SDBDEF
$SDDEF
$SDFDEF
$SDFMDEF
$SDFVDEF
$SDFWDEF
$SDVDEF
$SECDEF
$SECIDDEF
$SECSRVDEF
$SECSRVMSGDEF
$SGPSDEF
$SHRDEF
$SJCDEF
$SMBMSGDEF
$SMGDEF
$SMGMSG
$SMGTRMPTR
$SMRDEF
$SORDEF
$SRFDEF
$SRMDEF
$SSDEF
$SSIODEF
$STENVDEF
$STRDEF
$STSDEF
$SYIDEF
$SYSEVTDEF
$TBKDEF
$TEBDEF
$TIRDEF
$TPADEF
$TPUDEF
$TRMDEF
$TT2DEF
$TT3DEF
$TTCDEF
$TTDEF
$TTYDPORTDEF
$UAF070DEF
$UAIDEF
$UICDEF
$UIDDEF
$USGDEF
$USRIDEF
$UTCBLKDEF
$VADEF
$VAXDEF
$VA_RANGEDEF
$WBEMIDEF
$WWIDDEF
$XABALLDEF
$XABCXFDEF
$XABCXRDEF
$XABDATDEF
$XABDEF
$XABFHCDEF
$XABITMDEF
$XABJNLDEF
$XABKEYDEF
$XABPRODEF
$XABRDTDEF
$XABRUDEF
$XABSUMDEF
$XABTRMDEF
$XADEF
$XKDEVDEF
$XKSTSDEF
$XMDEF
$XWDEF
ACLEDIT$ROUTINES
CIADEF
CLI$ROUTINES
CMA$DEF
CONV$ROUTINES
CSHDEF
CVT$ROUTINES
DCX$ROUTINES
DTK$ROUTINES
EDT$ROUTINES
ELFDATYP
ELFDEF
ESFDEF
EVX_OPCODES
FDL$ROUTINES
LBR$ROUTINES
LIB$ROUTINES
LIBICB
MAIL$ROUTINES
MMEDEF
MTH$ROUTINES
NCS$ROUTINES
OTS$ROUTINES
PAGEDEF
PPL$DEF
PPL$ROUTINES
PSM$ROUTINES
SMB$ROUTINES
SMG$ROUTINES
SNAPEVTDEF
SOR$ROUTINES
STARLET
STR$ROUTINES
TBK$ROUTINES
TPU$ROUTINES
UTIL$ROUTINES
VERSION_INFO
$
<ur> lib BASIC$STARLET.TLB/text/extract=*                 ! dump all chapters to file BASIC$STARLET.TXT
<sr> $
<ur> lib BASIC$STARLET.TLB/text/extract=$IOSBDEF/out=BASIC$STARLET_$IOSBDEF.TXT
<sr> $
<ur> lib BASIC$STARLET.TLB/text/extract=$ILEDEF /out=BASIC$STARLET_$ILEDEF.TXT
<sr> $
<ur> lib BASIC$STARLET.TLB/text/extract=starlet /out=BASIC$STARLET_startlet.txt
<sr> $
<ur> dir basic$starlet*.txt/siz/width=file=30
<sr> Directory SYS$COMMON:[SYSLIB]

     BASIC$STARLET.TXT;12 8017
     BASIC$STARLET_$ILEDEF.TXT;1 9
     BASIC$STARLET_$IOSBDEF.TXT;2 8
     BASIC$STARLET_STARTLET.TXT;1 658

     Total of 4 files, 8692 blocks.
     $
<ur> edit/read BASIC$STARLET.TXT

Now that you've created a text file representation of the whole library called "BASIC$STARLET.TXT", use your favorite editor to open it, then search for the string "sys$qio" and you'll see the following:

   $QIO
 
     Queue I/O Request
 
      $QIO     [efn] ,chan ,func ,[iosb] ,[astadr] ,[astprm]
      ($QIOW)  ,[p1] ,[p2] ,[p3] ,[p4] ,[p5] ,[p6]
 
      efn    = number of event flag to set on completion
 
      chan   = number of channel on which I/O is directed
 
      func   = function code specifying action to be performed
 
      iosb   = address of quadword I/O status block to receive final
               completion status
 
      astadr = address of entry mask of AST routine
 
      astprm = value to be passed to AST routine as argument
 
      p1..p6 = optional device- and function-specific parameters
 
      EXTERNAL LONG FUNCTION  SYS$QIO     &
               (   LONG  BY VALUE       , &
                   WORD  BY VALUE       , &
                   WORD  BY VALUE       , &
                   BASIC$QUADWORD BY REF, &
                   LONG  BY REF         , &
                   LONG  BY VALUE       , &
                   ANY   BY REF         , &
                   LONG  BY VALUE       , &
                   LONG  BY VALUE       , &
                   LONG  BY VALUE       , &
                   LONG  BY VALUE       , &
                   LONG  BY VALUE         &
               )
Note: this info is only required when chasing strange compile-time bugs. Normally, the OpenVMS CD-ROM documentation is all you need to create and support a program employing system calls.

A Few OpenVMS Documentation Anomalies I've Discovered:

System Call Starlet
Definition
OpenVMS 7.2-1
CD-ROM (1999)
OpenVMS 7.3-1
CD-ROM (2002)
lib$bbcci long by ref,
long by value
always correct
long by ref,
address by ref
incorrect
long by ref,
address by value
correct
lib$bbssi long by ref,
long by value
always correct
long by ref,
address by ref
incorrect
long by ref,
address by value
correct

Example References

To properly reference BASIC$STARLET text library declarations from within OpenVMS-BASIC (DEC-BASIC, Compaq-BASIC, HP-BASIC) you'll need to employ something similar to this code fragment:

    !
    !       <<< system declarations >>>
    !
    %include "starlet"      %from %library "sys$library:basic$starlet"  ! system services (e.g. sys$qio)
    %include "$ssdef"       %from %library "sys$library:basic$starlet"  ! ss$
    %include "lib$routines" %from %library "sys$library:basic$starlet"  ! lib$
    %include "$uaidef"      %from %library "sys$library:basic$starlet"  ! uai$
    !
Note: Make sure to include every module required by your program.
      For more information just click here to check out some of my fully-functional free demo programs.

Example Program

1000    %title "timer_demo_xxx"                                                 !
        %ident "version_101.1"                                                  !
        option type = explicit                                                  ! no kid stuff...
        declare string constant k_program = "timer_demo"        ,               &
                                k_version = "101.1"                             !
        !=======================================================================
        ! title  : timer_demo_xxx.bas
        ! author : Neil Rieck
        ! created: 2004.01.01
        !=======================================================================
        set no prompt                                                           !
        !
        !       system declarations
        !
        %include "starlet"      %from %library "sys$library:basic$starlet"      ! system services
        %include "$ssdef"       %from %library "sys$library:basic$starlet"      ! ss$
        %include "lib$routines" %from %library "sys$library:basic$starlet"      ! lib$
        !
        !       home brewed functions
        !
        external long   function get_timer_bit_vector(long)                     ! required for used with SYS$WFLOR
        !
        declare long    rc%                                                     ,! return code                          &
                        timer_event_flag%                                       ,! timer event flag                     &
                        timer_ef_state%                                         ,! timer event flag state               &
                        tcp_event_flag%                                         ,! tcp event flag                       &
                        tcp_ef_state%                                           ,! tcp event flag state                 &
                        mask%                                                   ,! required for sys$wflor               &
                        junk%                                                   ,!                                      &
        basic$QuadWord  DeltaQuad                                                ! for sys$bintim etc.
        !
        !=======================================================================
        !       main
        !=======================================================================
        main:
        margin #0, 132                                                          ! width for the log file
        print k_program +"_"+ k_version                                         !
        print string$(len(k_program +"_"+ k_version), asc("="))                 ! underline previous line (how will this optimize?)
        !
        !       <<< get some event flags for later >>>
        !
        if tcp_event_flag% = 0 then                                             ! if not yet allocated
            rc% = lib$get_EF( tcp_event_flag% )                                 ! get an event flag
            if ((rc% and 7%) <> 1) then                                         !
                print "lib$get_EF-1 rc: ";str$(rc%)                             !
                goto rc_exit                                                    !
            end if                                                              !
        end if                                                                  !
        !
        if timer_event_flag% = 0 then                                           ! if not yet allocated
            rc% = lib$get_EF( timer_event_flag% )                               ! get another event flag
            if ((rc% and 7%) <> 1) then                                         !
                print "lib$get_EF-2 rc: ";str$(rc%)                             !
                goto rc_exit                                                    !
            end if                                                              !
        end if                                                                  !
        !
        !       <<< arm a timer to expire 'x' time from now >>>
        !
        print "-i- arming timer-1 (timer) for 10 seconds from now"              !
        declare string constant k_delay010 = "0 00:00:10"                       ! set delay time 10 seconds from now
        rc% = sys$bintim(k_delay010, DeltaQuad )                                ! init delta time ('x' time from now)
        print "-e- sys$bintim rc: "+ str$(rc%) if ((rc% and 1%) <> 1%)          !
        rc% = sys$setimr(timer_event_flag%,DeltaQuad by ref,,,)                 ! now use it to schedule a wake up
        print "-e- sys$setimr rc: "+ str$(rc%) if ((rc% and 1%) <> 1%)          !
        !
        !       <<< use a second timer to simulate some sort of TCP timeout >
        !
        print "-i- arming timer-2 (fake tcp) for 20 seconds from now"           !
        declare string constant k_delay020 = "0 00:00:20"                       ! set delay time 20 seconds from now
        rc% = sys$bintim(k_delay020, DeltaQuad )                                ! init delta time ('x' time from now)
        print "-e- sys$bintim rc: "+ str$(rc%) if ((rc% and 1%) <> 1%)          !
        rc% = sys$setimr(tcp_event_flag%,DeltaQuad by ref,,,)                   ! now use it to schedule a wake up
        print "-e- sys$setimr rc: "+ str$(rc%) if ((rc% and 1%) <> 1%)          !
        !
        ! note: for the SYS$WFLOR call to work, both event flags must be in the same event flag cluster.
        !       The first parameter is only used to determine which event flag cluster to test.
        !       The second parameter (mask) contains bits representing event flags within that cluster
        !
        mask% =                 get_timer_bit_vector(  tcp_event_flag%)         ! insert vector 1 into mask
        mask% = mask% or        get_timer_bit_vector(timer_event_flag%)         ! insert vector 2 into mask
        !
        !       <<< wait for either the 'TCP event flag' or the 'TIMER event flag' to change state >>>
        !
        print "-i- waiting for event flag "+ str$(tcp_event_flag%) +" or event flag "+ str$(timer_event_flag%)
        !
        rc% = sys$wflor( tcp_event_flag%, mask%)                                ! wait for a response from one of two flags
        print "-e- sys$waitfr rc: "+ str$(rc%) if ((rc% and 1%) <> 1%)          !
        !
        !       <<< cancel all timer requests (if any) >>>
        !
        print "-i- Calling $CanTim"                                             !
        rc% = sys$cantim(,)                                                     ! cancel all timer requests
        print "-e- sys$cantim rc: "+ str$(rc%) if ((rc% and 1%) <> 1%)          !
        !
        !       which event flag is set? TCP or TIMER?
        !
        rc% = sys$readEF(tcp_event_flag%, junk%)                                ! test TCP event flag
        select rc%                                                              !
            case SS$_WASCLR                                                     !
                tcp_ef_state% = 0                                               !
            case SS$_WASSET                                                     !
                tcp_ef_state% = 1                                               !
            case else                                                           !
                print "-e- sys$readef-tcp rc: "+ str$(rc%)                      !
        end select                                                              !
        print "-i- TCP EF State  : ";str$(tcp_ef_state%)                        !
        !
        rc% = sys$readEF(timer_event_flag%, junk%)                              ! test TIMER event flag
        select rc%                                                              !
            case SS$_WASCLR                                                     !
                timer_ef_state% = 0                                             !
            case SS$_WASSET                                                     !
                timer_ef_state% = 1                                             !
            case else                                                           !
                print "-e- sys$readef-timer rc: "+ str$(rc%)                    !
        end select                                                              !
        print "-i- Timer EF State: ";str$(timer_ef_state%)                      !
        !
        !       at this point either the TCP-EF or the TIMER-EF could be set
        !
        if (timer_ef_state% = 1)        and                                     ! if the TIMER-EF is set                &
           (  tcp_ef_state% = 0)                                                ! and the TCP-EF is clear
        then                                                                    ! then something timed out
            print "-i-the tcp event timed out"
        end if

        !=======================================================================
        !       <<< adios... >>>
        !=======================================================================
        fini:
        rc% = 1                                                                 ! vms -s- 
        !
        !       rc% must be set up b4 this point (and must not be changed)
        !
        rc_exit:
30000   end program rc%                                                         !
        !#######################################################################
        !
        !       <<< external functions >>>
        !
        !======================================================================
        !       get timer bit vector
        !       (see OpenVMS system systevices documentation for "sys$wflor")
        !
        !       notes:  cluster event flags
        !               0       00- 31
        !               1       32- 63
        !               2       64- 95
        !               3       96-127
        !======================================================================
31040   function long get_timer_bit_vector(long event_flag)
        option type = explicit
        declare long temp
        !
        select event_flag
            case <= 31
                temp = event_flag
            case <= 63
                temp = event_flag - 32
            case <= 95
                temp = event_flag - 64
            case else
                temp = event_flag -96
        end select
        !
        select temp                                                             ! this code will avoid an integer overflow
            case 31                                                             ! need to set bit #31
!                                        33222222222211111111110000000000
!                                        10987654321098765432109876543210
                get_timer_bit_vector = B"10000000000000000000000000000000"L     ! so return this
            case else                                                           !
                get_timer_bit_vector = (2% ^ temp)                              ! else return this
        end select
        !
        end function                                                            ! get_timer_bit_vector
        !
        !#######################################################################

Back to OpenVMS Resources
Back to OpenVMS Demos
Back to Home
Neil Rieck
Kitchener - Waterloo - Cambridge, Ontario, Canada.