AOH :: P35-07.TXT

Users Guide to VAX/VMS Part 1 of 3



                                ==Phrack Inc.==

                Volume Three, Issue Thirty-five, File 7 of 13

      <:=--=:><:=--=:><:=--=:><:=--=:>\|/<:=--=:><:=--=:><:=--=:><:=--=:>
      <:=--=:>                                                   <:=--=:>
      <:=--=:>    >>>>>=-*  Users Guide to VAX/VMS  *-=<<<<<     <:=--=:>
      <:=--=:>                                                   <:=--=:>
      <:=--=:>                   Part I of III                   <:=--=:>
      <:=--=:>                                                   <:=--=:>
      <:=--=:>            Part A:  Basic Information             <:=--=:>
      <:=--=:>         Part B:  Programming the VAX/VMS          <:=--=:>
      <:=--=:>                                                   <:=--=:>
      <:=--=:>                   By: Black Kat                   <:=--=:>
      <:=--=:>                                                   <:=--=:>
      <:=--=:><:=--=:><:=--=:><:=--=:>/|\<:=--=:><:=--=:><:=--=:><:=--=:>


Index
~~~~
Part A contains information on the following topics:

   o  Background                          o  Logical Names
   o  Terminal Control Keys               o  System Default Logical Names
   o  Logging in                          o  Logical Name Tables
   o  Digital Command Language (DCL)      o  User Environment
   o  Error Messages                      o  Terminal Characteristics
   o  Command Line Editing                o  File Security
   o  Files and Directories               o  EDT Text Editor
   o  File Operations                     o  EDT Help manual

Part B contains information on the following topics:

   o  Programming VAX/VMS              o  Parameters
   o  DCL Expressions                  o  Terminal I/O
   o  Command Procedures               o  File I/O
   o  Writing Command Procedures       o  Redirecting Command Procedure I/O
   o  Comments                         o  Branching and Conditionals
   o  Labels                           o  Loops
   o  Debugging                        o  Subroutines
   o  Invoking Command Procedures      o  Error Handling
   o  Symbols                          o  Termination
   o  Lexical Functions                o  Example Command Procedures


                   <:=- Part A : Basic Information -=:>

Introduction
~~~~~~~~~~~
VAX is an acronym for Virtual Address eXtension, a 32-bit computer developed by
Digital in the 1970's.  The VAX architecture supports multiprogramming, where
many users running different programs can use the VAX simultaneously and each
appears to have full control of the computer's resources.  The multiprocessing
VAX functions vary differently from the old timesharing systems, which would
allocate a slice of CPU time to each user of the system in a rotating fashion,
whether the time slice was required or not.  The VAX/VMS environment, however,
provides each user an allocation of processor time based on the user's needs
and priority. If a user does not need his quantum of time, or a portion of it,
it is given to the next user.  This scheduling method is very efficient when
compared to the old method of timesharing.

The VAX is capable of addressing more than four billion addresses, through a
method known as virtual memory addressing.  Because the memory is virtual
however, there is no need to have four billion bytes of physical memory.  The
VAX executes programs by a technique known as paging, whereby a single "page"
of the program is read into memory at a time, and when a new page is needed,
the old one is "swapped" back out to disk to make room for the new one.  The
VMS operating system ties everything together.  The user interacts with VMS
(Virtual Memory System) through a Command Language Interpreter (CLI), usually
the Digital Command Language (DCL).

When you use VAX/VMS, you are known to the system as a process, which is
created when you log in to the system and deleted when you log out.  This
process carries with it various attributes to identify you from other system
users (process name, identification, user identification code, privileges,
etc).


Terminal Control Keys
~~~~~~~~~~~~~~~~~~~
Ctrl-A      Allows you to insert, rather than overstrike, characters on a
            DCL command line that you're editing.
Ctrl-B      Displays DCL commands that you've previously entered.
Ctrl-C      Interrupts the coessed or the program being executed.
Ctrl-E      Positions the cursor at the end of the line.
Ctrl-H      Positions the cursor at the beginning of the line.
Ctrl-I      Tab
Ctrl-O      Alternately suppresses and continues the display of the output
            terminal.
Ctrl-Q      Enables (toggles on) output to the display after CTRL-S.
Ctrl-R      Retypes the current input line and repositions the cursor atthe
            end of the retyped line.
Ctrl-S      Disables (toggles off) output to the display until CTRL-Q is
            pressed.
Ctrl-T      Displays process statistics.
Ctrl-U      Discards the current input line and performs carriage return.
Ctrl-W      Refreshes the screen.
Ctrl-X      Flushes the type-ahead buffer.
Ctrl-Y      Interrupts command or program execution and returns control to
            the DCL command line interpreter.
Ctrl-Z      Indicates end of file for data entered from terminal.


Logging in
~~~~~~~~
Most VAX systems prompt you with something like this:

   Welcome to VAX1
   Username:

Type your username and press <enter>.  You'll then be prompted for your
password.  If you enter the correct username/password combination, you'll
be given something like the following:

          Welcome to VAX/VMS V4.4
   Last interactive login on Monday, 16-JUL-87  16:12
   Last non-interactive login on Friday, 13-JUL-87  00:14
   $

If you entered an incorrect username and password, you'll receive the
message:

   User authorization failure

Just hit <enter> and you'll be prompted for your username again.  Once
you're logged in, you'll be given the DCL prompt ($).  This indicates that
the system is ready to accept interactive commands.

To log out, use the command:

   $ LOGOUT


The Digital Command Language (DCL)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DCL is comprised of more than 200 commands called verbs.  Each DCL verb acts on
a parameter or assumed parameter, and the action of these verbs and the scope
of their parameters can be modified with qualifiers.  The basic command
structure is:

$ LABEL: COMMAND-NAME PARAMETER(S) /QUALIFIER(S) !COMMENT
    |           |         |             |           |
    |           |         |             |           +-- Optional Comment
    |           |         |             |
    |           |         |             +-------------- Command modifier(s)
    |           |         |
    |           |         +---------------------------- Object of the
Command
    |           |
    |           +-------------------------------------- DCL command verb
    |
    +-------------------------------------------------- Optional Label

A label is an optional, user-specified string with a maximum length of
255 characters.  It is most commonly used in command procedures.

A DCL command verb defines the action the VAX will take when the command
line is interpreted.

Parameter(s) specify the object or a list of objects the DCL command verb
will act upon.  Multiple parameters may be specified but must be separated
from one another by a space, multiple spaces, or a tab.  If you enter a DCL
command that requires parameters, but you don't enter them on the command
line, the DCL interpreter will prompt you for them automatically.

Qualifiers further define or modify the function the DCL command will
perform.  They consist of a keyword followed by a value or a list of
values.

The qualifier keyword must be preceded by a slash (/).  Multiple qualifiers
may be specified, but each must be preceded with a slash.  Qualifiers
usually aren't required.  There are three kinds of qualifiers:  parameter,
positional, and command.  A command qualifier applies to the whole command.
Generally, these are placed at the end of the command.  For example:

   $ DIRECTORY [BYNON],[BYNON.DECPRO]/FULL

This displays a full listing of two directories, using the /FULL qualifier of
the DIRECTORY command.  A positional qualifier takes on a different meaning
based on where it is located in the command.  If a positional qualifier is
placed after the command verb, but before the first parameter, the qualifier
will affect the entire command.  If the same positional qualifier is placed
after a parameter, only that parameter will be affected.  For example:

   $ PRINT/COPIES=3 MEMO1.TXT,MEMO2.TXT
   $ PRINT MEMO1.TXT/COPIES=2,MEMO2.TXT

The first command prints three copies of each file.  The second command prints
two copies of the first file, but only one copy of the second.  A parameter
qualifier affects only the parameter it follows.  In the following example,
MEMO1.TXT is sent to the queue LASER and MEMO2.TXT is sent to queue FAST_PRINT:

   $ PRINT MEMO1.TXT/QUEUE=LASER,MEMO2.TXT/QUEUE=FAST_PRINT

A comment is an optional, user-specified comment about the command.  It is
commonly used in command procedures to document the command.


Error Messages
~~~~~~~~~~~~
Generally, error messages are of the format:

   % FACILIT-L-IDENT, TEXT
   |   |     |   |      |
   |   |     |   |      +-- explanation of the error message
   |   |     |   |
   |   |     |   +--------- abbreviated message text, for reference
   |   |     |
   |   |     +------------- error severity
   |   |
   |   +------------------- Vax/VMS facility or component (error source)
   |
   +----------------------- message number: "%" = first, "-" = subsequent

A percent sign (%) indicates the first error message for a given command.
All subsequent errors for that command are preceded with a hyphen (-).

The facility indicates the source of the error.  The source may be the DCL
command line interpreter, one of the various VMS utilities, or a program
image.

The severity level indicator (L) will have one of the following values:
S (successful completion), I (information), W (warning), E (error), or
F (fatal or severe error).

The ident is an abbreviation of the error message text.  It can be referenced
in the VAX/VMS System Messages manual.

The text provides an explanation of the error message.


Command line editing
~~~~~~~~~~~~~~~~~~
DCL stores the last 20 command lines entered.  You can display a list of them
with:

   $ RECALL /ALL

The resulting display might look like:

   1  DIR
   2  COPY VAX1::$1$DUA5:[BYNON]LOGIN.COM LOGIN.COM;1
   3  EDIT LOGIN.COM
   $

To recall a specific command from the recall buffer, use the DCL RECALL
command with a command line number as a parameter.  For example:

   $ RECALL 2
   $ COPY VAX1::$1$6DUA5:[BYNON]LOGIN.COM LOGIN.COM;1


Files and Directories
~~~~~~~~~~~~~~~~~~~~
Files are organized much like MS-DOS, with a directory-tree structure.  The
user's default directory (assigned by the system administrator) is the "root"
directory.  Up to seven subdirectories may be created, each containing as many
subdirectories as you like.  The complete file specification looks like:

   VAX1 :: DUA0 : [BYNON.PROGRAMMING.FORTRAN]WINDOWS.FOR;3
    |       |                |                  |     |  |
    |       |                |                  |     |  |
   node   device         directory          filename  |  version
                                                     type
                                                     
The node name identifies a computer system in a network.  If no node name is
specified, VMS assumes the file is located on the local node where you're
logged in.

The device name is the physical device where the file is stored.  It is a
four-character alphanumeric code which identifies the device type, hardware
controller to which it is attached, and the unit number of the device on the
controller.  If you omit the device name from a file specification, VMS assumes
you are referring to your default device.

The directory entry is enclosed in brackets, and is the name of the directory
that contains the file.  If you omit the directory name from a file
specification, VMS will assume you are referring to your default directory.

The filename may consist of up to 39 alphanumeric characters.

The file type is a code consisting of up to 39 alphanumeric characters, and it
generally indicates the type of information supplied in the file.  Some system
programs and utilities supply a three character default file type.

The version number is a 1 to 5 digit number the system assigns to every file by
default.  When a file is created, it is assigned a version number of 1.  Each
time the file is edited or another version of it is created, the version number
is automatically incremented by 1.  Alternatively, you may specify a version
number of your choice.

No blank spaces are allowed within any portion of a file specification.  In
VMS Version 4.x, the maximum lengths are as follows:

   node name           up to 6 characters
   device name         four characters
   directory name      up to 39 characters
   subdirectory name   up to 39 characters
   file name           up to 39 characters
   file type           up to 39 characters
   version number      up to 5 decimal digits with a value between 1
                       and 32,767

File specifications must be unique; no two files can have completely identical
specifications.  It's conceivable to have many copies of NOTES.TXT in a
subdirectory, but only one NOTES.TXT;8 may exist in the same subdirectory.

Wildcards are similar to those in MS-DOS, with an asterisk (*) representing
a filename or filetype, and a percent sign (%) indicating a single
character.


File operations
~~~~~~~~~~~~~~
Creating and modifying files:  $ CREATE TEMP.DAT
                               TEMP 1
                               TEMP 2
                               <CTRL-Z>

Renaming files:   $ RENAME TEMP.DAT NEW.DAT
                  $ RENAME TEMP.DAT [BYNON.PROG]TEMP.DAT
                  Note: you cannot rename files across devices, just
                  directories.

Copying files:    $ COPY TEMP.DAT NEW.DAT
                  $ COPY TEMP.DAT,TEST.DAT NEW.DAT

Appending files:  $ APPEND TEMP.DAT NEW.DAT

Deleting files:   $ DELETE TEMP.DAT;1
                  $ DELETE *.DAT;*
                  $ DELETE /CONFIRM .DAT;*  (confirm each file)

Displaying files: $ TYPE /PAGE TEMP.DATE    (one page at a time)

Directories:      $ DIRECTORY
                  $ DIRECTORY DJA1:[BYNON.PROG]

Printing files:   $ PRINT TEMP.DAT

Purging files:    $ PURGE *.DAT   (erase all but latest version of .DAT files)

Create a dir:     $ CREATE/DIRECTORY [.BUDGET]

Set default dir:  $ SET DEFAULT [BYNON.PROG]
                  $ SET DEFAULT [.PROG]

Delete a dir:     $ SET DEFAULT [BYNON.PROG]
                  $ DELETE *.*;*
                  $ SET DEFAULT [BYNON]
                  $ SET PROTECTION=(0:D) PROG.DIR;1
                  $ DELETE BUDGET.DIR;1


Logical Names
~~~~~~~~~~~~
A logical name is a substitute for a file specification, portion of a file
specification, or another logical name.  They provide two primary functions:
file and device independence and file specification shorthand.

File and device independence means that you are not constrained by a physical
element, such as a disk or printer name.  If you use files nested deeply in
subdirectories, with long names, or on devices or nodes other than your
default, you can define a meaningful logical name to represent it.  These
shorthand names are faster to type and easier to remember.

To define a logical name:

   $ DEFINE PARTS_DBF DJA2:[DATABASES]PARTS.DAT

This example will associate the logical name PARTS_DBF with the file
specification  DJA2 : [DATABASES]PARTS.DAT.  Now, PARTS_DBF may be used
anywhere as a substitute for the complete file specification.

Other commands also can be used to assign logical names.

Assign  :  Associates equivalence names with a logical name
Mount   :  Mounts a disk or tape volume and assigns a system logical for the
           volume.
Allocate:  Allocates a system device for private use and optionally (command
           qualifier) assigns a logical name to the device.
Open    :  Opens a file for read or write operations and assigns a logical
           name to the file specification.

To display the logical name translations: $ SHOW LOGICAL PARTS_DBF will
display: "PARTS_DBF" = "DJA2:[DATABASES]PARTS.DAT"  (LNM$PROCESS_TABLE).

To deassign a logical name:  $ DEASSIGN  PARTS_DBF


System default logical names
~~~~~~~~~~~~~~~~~~~~~~~~~~~
SYS$COMMAND   The initial file, or input stream, from which the DCL command
              line interpreter reads input data.  The logical name
              SYS$COMMAND is equated to your terminal for interactive
              processes.
SYS$DISK      Your default disk as assigned in the UAF.
SYS$ERROR     The device on which the system displays all error and
              informational messages.  By default, SYS$ERROR is assigned
              to your terminal for interactive processes, and to the batch
              job log file for any batch processes.
SYS$INPUT     The default file or input stream from which data and commands
              are read by either the DCL command line interpreter or
              programs executing in your account.  By default, SYS$INPUT is
              equated to your terminal for interactive processes and to the
              batch job stream (or command procedure) for batch processes.


Logical Name Tables
~~~~~~~~~~~~~~~~~
Logical names are stored in system files called logical name tables.
The following are the four most commonly used:

Group table  :  Contains the logical names available to all users in your
                UIC (User Identification Code) group.
Job table    :  Contains the logical names available to your process and
                any subprocess it creates.
Process table:  Contains the logical names available to your process only.
System table :  Contains the logical names that may be used by all users
                of the system.


User Environment
~~~~~~~~~~~~~~
The User Authorization File (UAF) is a system file controlled and modified
by the system manager.  A record for each system user is contained in the
UAF.

A User Identification Code (UIC) is an identifier used by VAX/VMS to identify
users and groups of users.  It is used to identify processes, directories,
files, and other objects in the system.  A UIC may be specified numerically or
alphanumerically, and is made up of two parts, a group and a member, specified
in the format: [group,member].  For example, UIC [10,14] identifies group 10,
user 14.  The group number is an octal number in the range 1-37776, and the
member is an octal number in the range 0-177776.  An alphanumeric UIC contains
a member name and optionally, a group name in the format: [member] or
[group,member].  The group and member names in an alphanumeric UIC may contain
1 to 31 alphanumeric characters (A-Z, 0-9, underscore, dollar sign).

Each user of the system is limited in the consumption of system
resources, and these limits control the rate at which your process or
any subprocesses you create may consume a resource.  There are 32 levels
of priority in the VAX/VMS system, 0 through 31, the highest being 31.
The priorities are divided into two ranges: timesharing (0-15) and
real-time (16-31).  The default user priority is 4.  Depending on how
heavily the system is being used, your priority may be raised above the
default, but never lowered below it.  VAX/VMS maintains 35 privileges,
divided into the following seven categories classified by how much
damage could be done to the system by possessing them:

None    No privileges.
Normal  The minimum privilege needed to use the system effectively.
Group   The ability to effect members of the same UIC group.
Devour  The potential to consume noncritical system-wide resources.
System  The ability to interfere with normal system operation.
File    The potential to bypass file protection security.
All     The ability to take over the entire system.

VAX/VMS systems keep a record of overall computer system use by account
holder in a system file called ACCOUNTING.DAT.  The system manager uses
this file to produce reports with the Accounting Utility.  This can be
used to learn more about how the system is being used, how it performs,
and how a particular user is using the system.  It can also be used to
bill users for system time.


Terminal Characteristics
~~~~~~~~~~~~~~~~~~~~~~
Setting display width:  $ SET TERMINAL/WIDTH=132

Shutting messages off:  $ SET TERMINAL/NOBROADCAST
  This prevents other users from phoning you, sending mail messages, and
  some system messages from appearing on your screen.  If you just want
  mail and phone messages screened, use: $ SET BROADCAST=(NOMAIL,NOPHONE).

Increasing type-ahead buffer:  $ SET TERMINAL/ALTYPEHD/PERMANENT

Line editing modes:  $ SET TERMINAL/INSERT or $ SET TERMINAL/OVERSTRIKE

Defining keys:  $ DEFINE/KEY PF1 "SET DEFAULT DUA3:[INV.SUP]"
                % DCL-I-DEFKEY, DEFAULT key PF1 has been defined

Showing keys:   $ SHOW KEY PF1      (or $ SHOW KEY ALL)
                DEFAULT keypad definitions:
                   PF1 = "SET DEFAULT DUA3:[INV.SUP]"

Deleting keys:  $ DELETE/KEY PF1    (or $ DELETE/KEY ALL)
                % DCL-I-DELKEY, DEFAULT key PF1 has been deleted


Changing prompt:  $ SET PROMPT = "What now?"

Displaying process information:  $ SHOW PROCESS  (add a qualifier)

Changing process information:  $ SET PROCESS/NAME="Bob"
                               $ SET PROCESS/PRIVILEGES=OPER


File Security
~~~~~~~~~~~~
UIC-based protection permits access to be granted or denied based on
protection codes that reflect four user categories:

System:  system manager
Owner :  account owner
Group :  users in same UIC group
World :  all users of system, regardless of UIC

Four type of file access can be granted or denied to members of these user
categories:

Read    (R): read the file
Write   (W): create or modify the file
Execute (E): run a program
Delete  (D): delete the file

Generally, any category of user can be granted or denied file access
with this protection scheme.  However, you can read a file in a
subdirectory with EXECUTE access if you know its filename and filetype.
Also, since SYSTEM privileges include the ability to bypass all file
protection, anyone within the SYSTEM category can read a file.

CONTROL access, or the ability to change the protection and ownership of
a volume, is never specified in the UIC-based protection code.  This is
the fifth type of protection that can be specified in an access control
list (ACL).  It's automatically granted to two user categories when VMS
examines UIC-based protection.  Users in the SYSTEM and OWNER categories
receive CONTROL access by default while GROUP and WORLD categories are
denied CONTROL access.

File protection defaults are as follows:

System:  RWED
Owner :  RWED
Group :  RE
World :  No access

To determine the existing or default protection of a file, use the SHOW
PROTECTION command.  The default in the previous example would be:
   $ SHOW PROTECTION
       SYSTEM=RWED, OWNER=RWED, GROUP=RE, WORLD=NO ACCESS

If you want to see file protection in directories, use the /PROTECTION
qualifier with the DIRECTORY command.

To change the protection of a file, use the command:

   $ SET PROTECTION=(O:RWE,G,W) LOGIN.COM

In this example, the account owner has READ, WRITE, and EXECUTE access
to his LOGIN.COM file.  The GROUP and WORLD categories have no access
and SYSTEM access remains unchanged.

Rules for specifying protection codes:
1.  Access types must be abbreviated with one letter: R, W, E, or D.
2.  User categories may be spelled out or abbreviated.
3.  Each user category must be separated from its access types with a colon.
4.  If you specify multiple user categories, separate each with a comma
    and enclose the entire code in parenthesis.
5.  User categories and access types may be specified in any order.
6.  If you include a user category, but do not specify an access type
    for that category, access is automatically denied.
7.  If you omit a user category entirely, protection for that category
    is unchanged.

Remember that VAX/VMS evaluates directory protection before file
protection.  If you grant WORLD:R access to a file, but the file is in a
directory without WORLD:R access, another user couldn't read the file.


EDT Text Editor
~~~~~~~~~~~~~~
When you enter EDT, you automatically enter line mode, indicated by the
EDT prompt, an asterisk (*).  All line mode commands are made at the
asterisk prompt and terminated by pressing <Return>.  Lines that you
input are numbered sequentially by the editor.  You can reference a line
or group of li^S^Qnes based on the line number or range of line numbers.  A
list of basic EDT commands follows.  Each command may be abbreviated to
the characters in parenthesis.  Complete information on all EDT line
mode commands can be found through the use of the line mode EDT HELP
command.

Commands          Function
~~~~~~~         
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Change (C)        Change from line to keypad mode.  To switch back from
                  keypad mode to line mode, press <Ctrl-Z>.
Copy (CO)         Copy a line or group of lines from one place to another.
                  If you enter the command CO 5 to 10, line 5 will be
                  copied to the line immediately preceding line 10.  The
                  command CO 5:10 to 20 would copy the contents of lines 5
                  through 10 into the area immediately preceding line 20.
Delete (D)        Delete a line or group of lines.  The command D13 would
                  delete line 13, while D13:20 will delete lines 13 to 20.
Exit (EX)         Terminates the EDT session, saving all changes.  This
                  also creates a new version of the file being edited.
Help (H)          Display on-line help on all EDT line mode commands.  The
                  help messages will not be included in the file being edited.
Include (INC)     Copy text from an external file into the file being edited.
                  When the EDT command INCLUDE FILENAME.TYPE is executed,
                  the contents of FILENAME.TYPE are copied into the file
                  being edited.
Insert (I)        Inserts specified text directly before the current
                  position in the file.  While inserting text, you will
                  not receive the EDT "*" prompt.  Press <Ctrl-Z> to
                  return to the "*" prompt when you're finished inserting.
Move (M)          You can't cut and paste with a line-oriented editor.
                  Text will be moved to the area immediately preceding a
                  specified line.  The command M 10:15 to 50 would move
                  lines 10 through 15 to the area immediately preceding
                  line 50.
Quit (QUI)        Exit the EDT editor without saving changes.
Replace (R)       Deletes a specified line or group of lines and enters the
                  INSERT mode so you can add text in that place.  The
                  command R5:10 would delete lines 5 through 10 and switch
                  to the INSERT mode to permit you to enter new text.  To
                  exit the INSERT mode, press <Ctrl-Z>.
Resequence (RES)  Numbers all of the lines in the file that you're
                  editing in increments of 1.  This is useful because
                  text insertion, movement, or deletion causes the file
                  to lose numeric sequence.
Substitute (S)    Substitute a new text element for an old one in the
                  format s/oldtext/newtext/range.  The old and new text
                  elements must be enclosed in angle bracket (< >)
                  delimiters and the range must be specified.
Write (WR)        Write a given range of text to a new file.
                  WRHISTORY.TXT 50:100 would write lines 50 through 100 to
                  a new file called HISTORY.TXT.


EDT Help Manual
~~~~~~~~~~~~~
To dump the entire EDT Help file to disk, enter the following DCL command
during a terminal session:  $ ASSIGN EDTHELP.FIL SYS$OUTPUT.  Now, enter
line mode EDT and type:  * HELP *.  Now exit EDT and enter the DCL
command: $ ASSIGN TTnn: SYS$OUTPUTT (TTnn: is your terminal number).


                  <:=- Part B : Programming VAX/VMS -=:>

Introduction
~~~~~~~~~~~
A symbol is a name chosen to represent a string of characters, a numeric value,
or a logical (true/false) value.  A symbol may be used wherever the value it
represents would normally be found, and can be up to 255 characters long.
Symbols must begin with a character, dollar sign, or underscore, and are not
case-sensitive.  Symbols are created like this:

   symbol_name = value    (local symbol)
   symbol_name == value   (global symbol)

A global symbol may be used at any command level, but local symbols are lost
when command procedures are finished.  For example:

   $ WIDE = "SET TERMINAL/WIDTH=132"

Now, anytime you type WIDE at the DCL command line, the terminal width will
be changed to 132 characters.  To show the contents of a symbol:

   $ SHOW SYMBOL ANSWER
      ANSWER = 1584    HEX = 00000630    OCTAL = 000000003060

The SHOW SYMBOL command uses the local symbol table by default.  To show
the value of a global symbol, use the /GLOBAL qualifier.  To show all
symbols, use the /ALL qualifier (or /GLOBAL/ALL).  To delete symbols,
use: $ DELETE/SYMBOL symbol_name command (with /GLOBAL if it's global).

When a DCL command is executed, symbols in the following positions are
automatically translated:

  o  the beginning of the command
  o  in a lexical function
  o  in a WRITE or IF statement
  o  on the right side of an = or == assignment statement
  o  inside brackets on the left side of an assignment statement when
     you're preforming string substitution

If none of these cases fits, apostrophes will force the translation:
   $ DIRECTORY 'PARTS'  (after $ PARTS = "DJA2:[DBA]PARTS.DAT")

Symbols are commonly used for shorthand.  For example, to clear the screen:

   $ ESC[0,8] == 27
   $ CLEAR == "[J"
   $ HOME  == "[H"
   $ CLR == WRITE SYS$OUTPUT ESC,HOME,ESC,CLEAR

Now, anytime you enter CLR, the screen will be cleared.  Symbols can also be
used to execute command procedures:

   $ NETBACK == "@SYS$LOGIN:NETBACKUP"

Finally, foreign commands unknown to DCL can be executed by using symbols:

   $ KERMIT == RUN SYS$$SYSTEM:KERMIT


DCL Expressions
~~~~~~~~~~~~~~
Expressions are built by combining data elements with operators.  A logical
comparison evaluates the relationship between two components as true or
false (True = 1, False = 0).

Lexical functions are VAX/VMS routines that return process or system
information, or manipulate user-supplied data.  Lexical functions are unique
because the result is returned in the function name, allowing it to be used as
a symbol (much like Pascal).  Lexical functions are called with the following
format:

   F$function_name(parameter, parameter...)

For example, the following lexical function manipulates user-supplied data:

   $ STRING = "Go     home    right      now!"
   $ STRING = F$EDIT(STRING, "COMPRESS, UPCASE")
   $ SHOW SYMBOL STRING
      STRING = "GO HOME RIGHT NOW!"


Command Procedures
~~~~~~~~~~~~~~~~~
A command procedure is a file consisting of a sequence of DCL commands which
can be executed interactively or as a batch job (like a .BAT file in MS-DOS or
a REXX EXEC in VM/SP).  Command procedures are used in VAX/VMS to perform
repetitive or complex tasks and to save time.  With a command procedure, you
can execute many DCL commands with a single statement.

Command procedures aren't bound by simple lists of DCL commands executed in
sequence.  They can take advantage of labels, lexical functions, symbols and
relational operators to build sophisticated procedures which act like VAX/VMS
programs.  Command procedures are flexible.  They can be written to take
specific actions based on responses to questions, or even to perform a given
function depending on the time or date.


Writing Command Procedures
~~~~~~~~~~~~~~~~~~~~~~~
A text editor such as EDT or EVE is used to create and edit command procedures,
which should be named "PROCEDURE_NAME.COM".  The file type ".COM" is the
default procedure file type, and if a different file type is included, it must
be included when the procedure is invoked.

Each new command line must begin with a dollar sign ($).  Multiple spaces or
tabs may be included after the "$" for readability, and command lines may be
extended past a single line by ending the previous line with a hyphen (-) and
not starting the next line with a dollar sign.

Data input to programs, such as responses, must be entered without the dollar
sign.  Data lines are used by the program running and are not processed by the
DCL command line interpreter.  For example:

   $ MAIL         <--- invokes the Mail Utility
   SEND           <--- Mail SEND command
   JONES, BOB     <--- response to Mail prompt "To:"
   Memo           <--- response to Mail prompt "Subj:"
   Bob,           <--- Mail message

   How's it going?'?

   Joe
   $              <--- terminates Mail program
   $ EXIT         <--- terminates command procedure


Comments
~~~~~
Comments may be included by preceding them with an exclamation point (!),
which causes everything to the right of it to be ignored by the DCL command
interpreter.  Comments make command procedures easier to debug and modify
later.  Spelling DCL commands out rather than using the abbreviations also
makes the command procedure more readable.


Labels
~~~
Labels are used by the DCL command line interpreter for conditional
processing and repetitive looping.  Labels should be placed on separate
lines, making them easier to find.  Labels can be 255 characters long, may
not contain blanks, and must be terminated with a colon (:).


Debugging
~~~~~~
The SET VERIFY command tells DCL to display each command as it processes it.
This allows you to see where errors are generated, and how strings are
translated.  SET NOVERIFY turns the verify mode off.

The SHOW SYMBOL command displays the contents of defined symbols, and is
used to show the contents of a symbol in a command procedure as it is being
executed.


Invoking Command Procedures
~~~~~~~~~~~~~~~~~~~~~~~~~~
Command procedures may be invoked interactively by typing the "at" sign (@)
followed by the procedure name.  The file type must also be included if it is
not ".COM" (the default).  Command procedures may be invoked at the command
line or from within another command procedure, called nesting.  The DCL SUBMIT
command will place your command (job) in a batch queue with other jobs waiting
to be run.  Command procedures are generally submitted as batch jobs when you
want them to execute at a specific time, they will take a long time to run, or
when a job must run at a reduced priority.  The following command submits the
command procedure ACCOUNT.COM to the VAX/VMS batch processor:

   $ SUBMIT ACCOUNT
   Job ACCOUNT (queue SYS$BATCH, entry 103) started on SYS$BATCH

The SYS$BATCH queue is the default and is used unless otherwise specified with
the /QUEUE qualifier.  When VAX/VMS runs this job, a process with your rights
and privileges will be created and the procedure executed within that process.


Symbols
~~~~~~
Symbols may be local (single equal sign) or global (double equal sign).
Local symbols are recognized by DCL only at the command level at which it
was defined and more deeply nested levels (subsequently called command
procedures).  Global symbols are recognized at any command level.  Local
symbols should be used when the symbols is only needed for the duration of
the command procedure employing it.  You should only define global symbols
if you're going to use them in other command procedures or for the duration
of your login session.

An asterisk can be used to tell the command line interpreter (CLI) to accept
abbreviations.  For example:

   $ NO*TES == "@SYS$LOGIN:NOTES"

This tells the CLI to accept NO, NOT, NOTE, or NOTES as a valid abbreviation
for the NOTES command.  This notation is usevul for long symbol names.


Lexical Functions
~~~~~~~~~~~~~~~~
Lexical functions allow you to obtain basically the same information as DCL
SHOW commands.  However, it's easier to manipulate information which comes
from a lexical function.  As an example, the following two command give the
same information:

   $ SHOW TIME                  ! DCL SHOW TIME command
       12-JUN-1989 14:29:23
   $ WRITE SYS$OUTPUT F$TIME()  ! lexical function
       12-JUN-1989 14:29:25.17

The second command is more usable, however:

   $!  Show_Date.COM
   $!
   $ TIME&DATE = F$TIME()
   $ DATE = F$EXTRACT(0,11,TIME&DATE)
   $ WRITE SYS$OUTPUT DATE

This procedure displays only the date portion of the string returned by the
lexical function F$TIME().  (Use @SHOW_DATE to invoke it) VAX/VMS supports
lexical functions to manipulate text strings, convert data types, and return
information about the system, your process, symbols, files and devices.


Parameters
~~~~~~~~~
Eight reserved symbols (P1 through P8) are available to command procedures to
supply data to process.  By using these parameters in a command procedure,
different data can be specified each time it's run.  Parameter specification is
done on the command line where the procedure is called.  Unless designed to,
the command procedure will not prompt for parameters.  Parameters are separated
with spaces and may be character strings, integers, or symbols.  If you want to
skip a parameter, us a null string (" ").

   $! Add.Com
   $! command procedure to demonstrate passing parameters
   $! (add the first and third parameter)
   $!
   $  WRITE SYS$OUTPUT P1+P3

   $ @ADD 12 " " 14
   26

If a command procedure requires multiple letters or words as a single
parameter, enclose it in quotes and it will be treated as one parameter and
not converted to uppercase.


Terminal Output
~~~~~~~~~~~~
The WRITE and TYPE commands send data to the terminal.  TYPE is used to
display the contents of a file, but may also be used to print lines of text
from within a command procedure.  TYPE may only be used to output text
strings.  Since the WRITE command is processed be DCL, expressions, symbols
and lexical functions are evaluated before the data is sent to the
terminal.

The output expression must translate to a string and be sent to the logical
device SYS$OUTPUT, but may be a string, lexical function, symbol, or any
combination of the three.  Here's an example of a command procedure that
uses terminal output:

   $! Writing a simple text string
   $!
   $  WRITE SYS$OUTPUT "This is a test..."
   $!
   $! Displaying multiple lines at the terminal
   $!
   $  TYPE SYS$OUTPUT Warning!
          It's been 30 days since you changed
          your password.  Change it now!
   $!
   $! Writing a string with a lexical function
   $!
   $  WRITE SYS$OUTPUT " "HI' You are in directory "F$DIRECTORY()' "


Terminal Input
~~~~~~~~~~~
The INQUIRE command's default device is the terminal keyboard, while the
READ command must be told where to accept data from.  The INQUIRE command
prompts for input, reads data and assigns it to a symbol.  All data is
accepted as a character string and is converted to uppercase and compressed
(extra blanks removed).  The READ command prompts for input if the /PROMPT
qualifier is used, accepts data from a specified source and assigns it to a
symbol.  The data is accepted with no string conversion or compression
occurring.  Here's an example of a command procedure that uses terminal
input:

   $! Puts whatever you type in the symbol NAME
   $! the /NOPUNCTUATION qualifier will suppress the colon
   $! and space INQUIRE puts at the end of the prompt
   $!
   $  INQUIRE /NOPUNCTUATION NAME "What is your name? "
   $!
   $! Example of READ using SYS$INPUT (terminal) for data
   $!
   $  READ /PROMPT = "First value: " SYS$INPUT VALUE_1
   $  READ /PROMPT = "Second value: " SYS$INPUT VALUE_2
   $  WRITE SYS$OUTPUT VALUE_1," + ",VALUE_2," = ",VALUE_1+VALUE_2


File I/O
~~~~~~~
The basic steps to read and write files from within command procedures are
similar to most other languages.  Use the OPEN command to open the file.  If it
does not exist, OPEN will create it.  Use the READ or WRITE commands to read or
write text records from the file.  Use the CLOSE command to close the
 file when you're done.

To open a file for writing, you must use the /APPEND or /WRITE qualifier.  The
/WRITE qualifier creates a new file and places the record pointer at the
beginning of the file.  If the file already exists, a new version will be
created by OPEN/WRITE.  The /APPEND qualifier is used to add records to the end
of an existing file.  The file must already exist before using the OPEN/APPEND
command, and when the file is opened, the record pointer is placed at the end
of the file.

To open a file for reading, use the /READ qualifier (the default for the
OPEN command).  A file opened for reading may not be written to, and the
record pointer will initially be placed at the first record in the file.
Each time a record is read, the pointer is moved down to the next record.
The WRITE/UPDATE must be used to write over an existing record. Here's an
example of a command procedure using file input and output:

   $ OPEN/APPEND OUTPUT_FILE NEW.DAT
   $ OPEN/READ INPUT_FILE OLD.DAT
   $ READ INPUT_FILE RECORD
   $ WRITE SYS$OUTPUT "First record from OLD.DAT - ",RECORD
   $ WRITE OUTPUT_FILE "First record from OLD.DAT - ",RECORD

To open a file for both reading and writing, use both the /READ and /WRITE
qualifiers.  The record pointer will be placed at the first record in the file.
Using this method, however, you can only overwrite the record you most recently
read, and records you replace must be the same length.
                                                   

Redirecting Command Procedure I/O
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Command procedures often invoke VAX/VMS utilities, and these programs will
normally get input from the logical device SYS$INPUT.  While executing a
command procedure, SYS$INPUT is directed to the command procedure itself, and
this is why you can put command and data lines for a utility or program
directly in the procedure.  SYS$COMMAND defaults to the terminal from where a
command procedure is being executed, and by redirecting SYS$INPUT to
SYS$COMMAND you can use utilities and other programs interactively from command
procedures:

   $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND:
   $ EDIT JUNK.DAT

The /USER_MODE qualifier causes the re-assignment to be in effect only for
the next command.

Normally command procedure output is displayed at your terminal.  You may
redirect output to a file by using the /OUTPUT qualifier:

    $ @SHOW_TIME/OUTPUT = TIME.DAT

By default, DCL error and severe error messages are directed to the file
represented by the logical name SYS$ERROR, which usually points to your
terminal.  If you want to log error messages, simply redirect SYS$ERROR to
a file.  If you redirect SYS$ERROR without also redirecting SYS$OUTPUT, DCL
will send error messages to both, and you'll receive the error messages
twice -- at your terminal and in the file.

To completely suppress error messages you can redirect both SYS$ERROR
and SYS$OUTPUT to the null device (NL:) or you can use the SET MESSAGE
command to turn off all message output.  To suppress all messages, use:
SET MESSAGE/NOTEXT/NOIDENTIFICATION/NOFACILITY/NOSEVERITY.


Branching and Conditionals
~~~~~~~~~~~~~~~~~~~~~~~~~
You can use the DCL IF/THEN statements and conditional operators withing
command procedures to cause the execution of a command based on the
evaluation of a condition.  The basic use is:  $ IF condition THEN command.
The condition is a Boolean expression (True or False) and the command is
any legal DCL command.  The following is a list of conditional operators:

Operator        Function
~~~~~~~       
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.EQ. / .EQS.    Determines if two numbers/character strings are equal
.GE. / .GES.    Tests to see whether the first number/character string is
                greater than or equal to the second
.GT. / .GTS.    Determines if the first number/character string is greater
                than the second
.LE. / .LES.    Tests to see if the first number/character string is less
                than or equal to the second
.LT. / .LTS.    Determines if the first number/character string is less than
                the second
.NE. / .NES.    Tests to see whether the two numbers/character strings are
                not equal
.AND.           Combines two numbers with a logical AND   (boolean algebra)
.OR.            Combines two numbers with a logical OR    (boolean algebra)
.NOT.           Logically negates a value

The following is a command procedure using conditional branching:

   $! Time.Com
   $!
   $    TIME = F$TIME()
   $    HOUR = F$EXTRACT(12,2,TIME)
   $    IF HOUR .LT. 12 THEN GOTO MORNING
   $    IF HOUR .LT. 17 THEN GOTO AFTERNOON
   $    IF HOUR .LT. 18 THEN GOTO EVENING
   $    GOTO END
   $  MORNING:
   $    WRITE SYS$OUTPUT "Good morning!"
   $  AFTERNOON:
   $    WRITE SYS$OUTPUT "Good afternoon!"
   $  EVENING:
   $    WRITE SYS$OUTPUT "Good evening!"
   $  END:
   $    EXIT


Loops
~~
Loops are used to repeat a statement or group of statements until a
given condition is met.  DCL supports both DO WHILE and DO UNTIL loops.
The DO WHILE loop tests the condition before evaluation:

   $ LOOP:
   $    IF .NOT. condition THEN GOTO END
     .
     .
     .
   $    GOTO LOOP
   $ END:
   $    EXIT

The DO UNTIL loop executes the statement(s) and then tests the condition:

   $ LOOP:
     .
     .
     .
   $    IF condition THEN GOTO LOOP
   $    EXIT


Subroutines
~~~~~~~~
The DCL command GOSUB transfers execution control to a label and the RETURN
command terminates subroutine execution, returning control to the statement
after the GOSUB command.  Subroutines are useful where you need to do the same
series of commands repeatedly in different parts of a command procedure.  They
also make procedures easier to read and more compact.  The DCL commands GOSUB
and RETURN are not supported in VAX/VMS versions before VAX/VMS Version 4.4.
The following is an example procedure using a subroutine:

   $! Personal.Com
   $!
   $!     opens the personal info file
   $!
   $  OPEN/WRITE OUTPUT_FILE PERINFO.DAT
   $!
   $!     collect info
   $!
   $  INQUIRE RECORD "Enter full name"
   $  GOSUB WRITE_FILE
   $  INQUIRE RECORD "Enter address"
   $  GOSUB WRITE_FILE
   $  INQUIRE RECORD "Enter phone number"
   $  GOSUB WRITE_FILE
   $  CLOSE OUTPUT_FILE
   $  EXIT
   $!
   $!     subroutine WRITE_FILE
   $!
   $  WRITE_FILE:
   $      WRITE OUTPUT_FILE RECORD
   $      RETURN


Error Handling
~~~~~~~~~~~~~
The command interpreter will execute an EXIT command if a severe error occurs,
terminating the procedure and returning control to the previous command level,
unless the DCL ON command is used to specify an action for the command
interpreter to take.  The ON command supports the three keywords WARNING,
ERROR, and SEVERE_ERROR.  To override error handling for procedure warnings,
for example, use something like this:

   $ ON WARNING THEN EXIT
     or
   $ ON WARNING THEN GOTO label

WARNING causes the command procedure to take action if a warning, error, or
severe error occurs.  ERROR causes the action if an error or severe error
occurs, and SEVERE_ERROR causes the action only if a fatal error occurs.

$STATUS and $SEVERITY are reserved DCL global symbols, and each time a command
is executed, values are assigned to these symbols. $STATUS holds the full
condition code of the last statement and $SEVERITY holds an error severity
level.  The condition code in $STATUS is valid to the VAX/VMS MESSAGE facility
and can be used in conjunction with F$MESSAGE to obtain the actual text message
associated with the code:

   $ SET DEFAULT DUB1:[BYNON]
   $ WRITE SYS$OUTPUT $STATUS $X00000001
   $ WRITE SYS$OUTPUT F$MESSAGE(%X00000001)
   % SYSTEM-S-NORMAL, normal successful completion

All DCL commands will return a condition code, but not all condition codes
have text messages.  Condition codes without text messages will return the
message "%NONAME-E-NOMSG Message number (8-digit code)".

The message text isn't very useful for making conditional decisions though, so
$SEVERITY is used.  It contains one of five possible values extracted from the
first three bits of $STATUS.  Here are the codes:

Code  Definition
~~~  ~~~~~~~~~~
 0    Warning
 1    Success
 2    Error
 3    Information
 4    Severe Error

Odd values (1,3) indicate success while even values (0,2,4) indicate failure.
There are basically two ways to use the status and severity codes to handle
errors.  The first is to treat $STATUS as a Boolean value:

   $ SET NOON
   $ command                         ! a DCL command
   $ IF $STATUS THEN GOTO NO_ERR     ! test $STATUS for T or F
     .
     .                               ! handle the error
     .
   $ NO_ERR                          ! continue processing
     .
     .
     .
   $ EXIT

The second method is to trap the error with the ON WARNING command, then use
the severity level to determine an appropriate course of action:

   $ SET NOON
   $ ON WARNING GOTO ERR_TRAP
   $ command                         ! a DCL command
   $ command                         ! a DCL command
     .
     .
     .
   $ EXIT
   $!
   $! error trap code
   $!
   $ ERR_TRAP:
   $    SEVERITY = $SEVERITY             ! save the error code
   $    IF SEVERITY = 0 THEN command     ! if warning...
   $    GOTO DONE
   $    IF SEVERITY = 2 THEN command     ! if error...
   $    GOTO DONE
   $    IF SEVERITY = 4 THEN command     ! if severe error...
   $ DONE:
     .
     .
     .
   $ EXIT

Error checking can be completely disabled with the SET NOON command.  When
this is in effect, the command interpreter continues updating the condition
code, but does not perform any error checking.  The DCL command SET ON
restors error checking to normal.  For example:

   $ SET NOON      ! turn off error checking
   $ command       ! a DCL command
   $ SET ON        ! restor error checking


Termination
~~~~~~~~~~
The EXIT command will terminate the current command procedure and return
control to the command level that called it while the STOP command terminates
all command procedures (if nested) and returns control to DCL.


Example Command Procedures
~~~~~~~~~~~~~~~~~~~~~~~~~
The following are two example command procedures to demonstrate some of
the previously discussed techniques.

Login.Com
~~~~~~~~
   $! Login.Com - executed each time you log in
   $!
   $! Check for a network or batch login
   $!
   $      IF F$MODE() .EQS. "NETWORK" THEN GOTO NETWORK
   $      IF F$MODE() .EQS. "BATCH" THEN GOTO BATCH
   $!
   $! Define process permanent symbols for convenience
   $!
   $      SD == "SET DEFAULT"
   $      SH == "SET HOST"
   $      WI*DE == "SET TERMINAL/WIDTH=132"
   $      NA*RROW == "SET TERMINAL/WIDTH=80"
   $      DIR*ECTORY == "DIRECTORY/SIZE"
   $      PU*RGE == "PURGE/LOG/KEEP=2"            ! keep latest 2 version
   $      HO*ME == "SET DEFAULT SYS$LOGIN:"
   $      WHO == "SHOW USERS"
   $      EVE == "EDIT/TPU"
   $      EDT == "EDIT/EDT/COMMAND=SYS$LOGIN:EDTINI.EDT"
   $      BR*OWSE == "TYPE/PAGE"
   $!
   $! Define special keys
   $!
   $      DEFINE/KEY/NOLOG/TERM PF1 "DIR"         ! term ends with <enter>
   $      DEFINE/KEY/NOLOG PF2 "EDIT"
   $      DEFINE/KEY/NOLOG/TERM/NOECHO PF3 "LOGOUT"
   $      DEFINE/KEY/NOLOG/TERM/NOECHO HELP "SHOW KEY/ALL"
   $!
   $! Modify terminal characteristics
   $!
   $      SET TERMINAL/INSERT     ! insert mode
   $      SET PROMPT = "[BYNON]> "
   $!
   $! Show time and quit
   $!
   $      SHOW TIME
   $      EXIT
   $!
   $! If it's a network login, we can now
   $! perform some other commands if desired.
   $! Just quit for now though.
   $!
   $  NETWORK:
   $      EXIT
   $!
   $! If it's a batch job login, set verification on and quit.
   $!
   $  BATCH:
   $      SET VERIFY
   $      EXIT


Subdir.Com
~~~~~~~~~
   $! Subdir.Com - how to search and parse character strings
   $!
   $      WRITE SYS$OUTPUT F$DIRECTORY()+ " Subdirectories:"
   $      WRITE SYS$OUTPUT " "
   $!
   $! Search for subdirectory names and display them on the terminal
   $!
   $  DIR$LOOP:
   $      FILE = F$SEARCH("*.DIR")
   $!
   $! If DCL returns a null string (" ") we're done
   $!
   $      IF FILE .EQS. " "THEN GOTO END$DIR$LOOP
   $!
   $! Find the position of the period
   $!
   $      DOT = F$LOCATE(".",FILE)
   $!
   $! Find the position of the right bracket
   $!
   $      BRACKET = F$LOCATE("]",FILE)
   $!
   $! Extract the string between the dot and bracket
   $!
   $      FILE = F$EXTRACT(BRACKET+1,DOT-BRACKET-1,FILE)
   $!
   $! Display the subdirectory name and start over
   $!
   $      WRITE SYS$OUTPUT "      ' 'FILE' "
   $      GOTO DIR$LOOP
   $  END$DIR$LOOP:
   $      EXIT                                              

<END PART I>
______________________________________________________________________________

AOH Site layout & design copyright © 2006 AOH