2012/11/30

Playing with descriptors in HP Pascal

Some times you want to have the possibility to pass multiple parameters of the same type to a function or procedure. HP Pascal makes this possible by using the [LIST] attribute. For more information on the attribute [LIST] and the ARGUMENTand ARGUMENT_LIST_LENGTHpredeclared routines, see the HP Pascal for OpenVMS - Language Reference Manual.

The problem I faced was that I wanted to use STRING parameters. This only works when you define a type based on STRING, e.g.
TYPE
    t_string_20 : STRING(20);
When you do so, and define a procedure like this:
PROCEDURE p( p_text : [LIST] t_string_20 );
then you can only pass parameters that have been declared using t_string_20. Of course that was not what I wanted.

After playing around with this problem for a while, I came up with the following solution. If the procedure is declared as external, then the parameters are passed using descriptors. It is possible to specify STRING instead of t_string_20 in the declaration. The external definition for the procedure p mentioned above will be:
[EXTERNAL]
PROCEDURE p( p_text : [LIST] STRING ); EXTERNAL;
Now all that is left, is accessing the parameters within the actual procedure using the descriptors. This can be done in a hidden procedure definition, like this:
[HIDDEN]
PROCEDURE p_hidden( p_text : [LIST] DSC1$TYPE );
BEGIN
    { some code }
END;
The type DSC1$TYPE is defined in the environment file SYS$LIBRARY:STARLET.PEN (source: SYS$LIBRARY:STARLET.PAS) as follows:
DSC1$TYPE = RECORD
    DSC$W_MAXSTRLEN : $UWORD;
    DSC$B_DTYPE : $UBYTE;
    DSC$B_CLASS : $UBYTE;
    DSC$A_POINTER : UNSIGNED;
END;
To use it you have to add the environment file in the [INHERIT] attribute (again, for more info, see the language reference manual mentioned above):
[INHERIT ( 'SYS$LIBRARY:STARLET')]
Of course, now the hidden procedure p_hidden is not yet linked to the external define procedure p. This can be done by telling the compiler that the procedure p_hidden should be known to the outside world as procedure p. For this we can use the [GLOBAL] attribute. The procedure p_hidden now looks like this:
[HIDDEN,GLOBAL(p)]
PROCEDURE p_hidden( p_text : [LIST] DSC1$TYPE );
BEGIN
    { some code }
END;
In the implementation of procedure p_hidden, the parameters can be accessed using the predeclared ARGUMENT and the list length can be determined with ARGUMENT_LIST_LENGTH.
[HIDDEN,GLOBAL(p)]
PROCEDURE p_hidden( p_text : [LIST] DSC1$TYPE );
VAR
    d : DSC1$TYPE;
     i : INTEGER;
BEGIN
    FOR i := 1 TO ARGUMENT_LIST_LENGTH( p_text ) DO
    BEGIN
        d := ARGUMENT( p_text, i );
    END;
END;
Now the descriptor can be accessed. Since I work with STRING parameters, I only want to allow descriptor type DSC$K_DTYPE_VT and descriptor class DSC$K_CLASS_VS (both defined in SYS$LIBRARY:STARLET.PAS). So I can check those after fetching the parameter.
d := ARGUMENT( p_text, i );
IF ( d.DSC$B_DTYPE = DSC$K_DTYPE_VT )
    AND
    ( d.DSC$B_CLASS = DSC$K_CLASS_VS )
THEN BEGIN
    { do something with the parameter }
END;
To actually do something with the actual string data pointed to by the DSC$A_POINTER field, you need to do something smart, like type casting. A STRING in HP Pascal has a maximum length of 65535, and is compatible with VARYING OF CHAR. Since I had some trouble with typecasting with a STRING variable, I defined a type t_varying_max and a pointer t_varying_max_ptr to access the actual string data in the descriptor.
TYPE
    t_varying_max = VARYING [ 65535 ] OF CHAR;
    t_varying_max_ptr = ^t_varying_max;
VAR
    long_string_ptr : t_varying_max_ptr;
    work_buffer : t_varying_max;
The type t_varying_max_ptr can now be used to copy the parameter in a local buffer:
long_string_ptr := d.DSC$A_POINTER::t_varying_max_ptr;
work_buffer := long_string_ptr^;
Finally, the procedure could look like this:
[HIDDEN,GLOBAL(p)]
PROCEDURE p_hidden( p_text : [LIST] DSC1$TYPE );
TYPE
    t_varying_max = VARYING [ 65535 ] OF CHAR;
    t_varying_max_ptr = ^t_varying_max;
VAR
    long_string_ptr : t_varying_max_ptr;
    work_buffer : t_varying_max;
    d : DSC1$TYPE;
     i : INTEGER;
BEGIN
    FOR i := 1 TO ARGUMENT_LIST_LENGTH( p_text ) DO
    BEGIN
        d := ARGUMENT( p_text, i );
        IF ( d.DSC$B_DTYPE = DSC$K_DTYPE_VT )
            AND
            ( d.DSC$B_CLASS = DSC$K_CLASS_VS )
        THEN BEGIN
            long_string_ptr :=
                d.DSC$A_POINTER::t_varying_max_ptr;
            work_buffer := long_string_ptr^;
            WRITELN( work_buffer );
        END;
    END;
END;
The nice thing about this is that it also works with VAR parameters, so it is also possible to output strings this way. If a string passed as VAR parameter is not large enough, it is possible to check first if the data supposed to be written to it will fit in the parameter using the DSC$W_MAXSTRLEN field of the parameter.

I succesfully implemented split and join functions this way.

2012/11/29

OpenVMS commands for the Unix/Linux minded

As an OpenVMS Enthusiast, I would recommend anyone on Unix/Linux to move to OpenVMS. You might, or might not want to do so, but that is up to you. Anyway, if you want to try and play with it, you can always get an account at the DEATHROW OpenVMS Cluster.
OpenVMS does not by default have a shell like Unix/Linux. Instead, it has a command interpreter, which is very powerful. Most users that come from a different platform have problems with the command syntax. I recently found this link on Stack Overflow in an answer about the equivalent of the history command.
The page on the link above was not very well formatted, I provide the list of command equivalents here in a more readable form (btw. not verified any of them). The other information on the page is for some other post. There are several of these lists on the internet, so maybe I will post another one later.
OpenVMSUnix/LinuxDescription
APPENDcatConcatenates files. If contencs of file1 need to be placed at the end of file2 issue the following unix command.cat file1 >> file2
ASSIGN or DEFINE=(Bourne & Korn)
set (C shell)
in Bourne or Korn shell DIR = ls
in C shell set DIR ls
DIRlsList file in the current directory
ATTACHfg
BACKUPtar
pax
back up files into a tar file.
/INITtar -c
pax
Restore files.
/LISTtar -tList contents.
/LOGtar -vReport progress.
/NOREWINDtar -rWrite at end of existing backup (tar) files.
/RECORDtar -mUpdate file's modification date upon restore.
COPYcpCopy a file
COPYftpCopy to/from a nontrusted remote host.
COPYrcpCopy to/from a remote host.
COPY /CONFIRMcp -iConfirm before copying.
CREATE touchCreate or update a file.
/DIRECTORYmkdirCreate a subdirectory.
CREATE filenamecat << filenameCreate a file from the keyboard.
CREATE filenamecat
DEBUGdbxDebug a program.
DELETErmDelete a file.
DELETErmdirDelete an empty subdirectory.
/CONFIRMrm -iConfirm deletion.
/ENTRYlprmRemove queued line printer job.
/QUEUElprm -PRemove all jobs from the queue.
/LOGrm -eDelete files and list them as they are deleted.
/SYMBOLunsetGet rid of an environment variable.
DIFFERENCESdiffDisplay all differences in files or directories.
/MAXIMUM_DIFF= 1cmpDisplay first difference in two files (typically used with binary files).
/NUMBER NL:cat -nDisplay a file with line numbers.
/SLPdiff - eGenerate editing changes for the ed editor.
DIRECTORYlsList files.
DIRECTORY [...]ls -RDo a recursive directory/list of files.
DIRECTORY [...]findFind a file
DIRECTORY *.DIRls -dList directory name(s) only ls -Rd
/BY_OWNERls -l dir | grep ownerList only those files owned by a specifed user.
/COLUMNls -1List one file per line.
/DATEls -cList by creation/last modification.
/FULLls -lLong listing.
/FULL /TOTALduSummarize disk usage.
/MODIFIED /SINCE [...]find -mtime +nModified more than n days ago.
/MODIFIED /BEFORE [...]find -mtime +nModified more than n days ago.
/OWNERls -gInclude group (used with |).
/SIZEls -sInclude size.
DISMOUNT /UNLOADmt rewofmt offlineRewind and unload the tape.
DUMPodDump a file in various formats.
/HEXADECIMALod -hHexadecimal dump.
/OCTALod -oOctal dump.
EDIT /EDT,EDIT /EVE, EVEviScreen editor session.
EDIT /RECOVERvi -rRecover a screen editing session.
EXCHANGEddBack up, restore, and convert nonstandard files.
EXITexitTerminate a script.
HELPmanDisplay online reference pages.
HELP HINTSman -k topicDisplay a list of commands that correspond to the specified topic.
INQUIRE /NOPUNCTUATIONread choice?Prompt for a responce and put the response into an environment variable.
INITIALIZE device:fddisk -fmt deviceFormat a diskette.
LIBRARYarLibrary maintainer.
/CREATEar -crCreate library.
/EXTRACTar -xExtract modules.
/INSERTar -qInsert modules.
/LISTar -tList modules.
/REPLACEar -rReplace modules.
LINKldLink compiled source code into an executable image.
login procedure LOGIN.COM.login
.cshrc
.profile
.kshrc
Set of commands automatically executed at login time.
 On OpenVMS, LOGIN/CLI specifies an alternate command language interpreter.
LOGOUTlogout C shell
exit Bourne & Korn shell
Terminate a terminal session.
MAILmailInvoke the mail utility.
MERGEsort -mMerge sorted files.
MOUNTmountMount a tape.
ON CONTROL_C THENtrap 2Enable handler for Stop signal.
ON CONTROL_YonintrOn interrupt.
PHONEtalk tty nameCommunicate interactively with another user.
PRINTlprPrint a file on the default line printer.
/COPIES=Nlpr -#nPrint n copies.
/DELETElpr -rRemove file after printing
/FORMlpr -lnMake page n lines (default = 66)
/FORMlpr -nPrint n column output.
/FORMlpr -wnSet line width to n
/HEADERpr -h string | lprPrint a header on each page.
/NAME=jobnamelpr -JjobnameInclude job name on the first page of the job.
/NOFLAGlpr -hPrint with no header page.
/NOTIFYlpr -mSend mail upon completion.
/PAGES=(n,"")lpr +nBegin printing on page n.
/QUEUElpr -PqueuePrint a file on the specified queue.
READreadRead input (korn shell)
RECALL /ALLhistoryRecall command lines
REPLY /USERwriteSend a brief message to a logged-in user
RENAMEmvmove/rename a file(s)
/CONFIRMmv -iconfirm the move/rename of a file(s)
SEARCHgrepSearch files for strings.
/MATCH=NORgrep -vList only lines that do not match
/NOEXACTgrep -iIgnore case distinctions.
/NUMBERSgrep -nPrecede each match with line number.
/STATISTICSgrep -cList only a file name that contains match
/WINDOW = 0grep -lReturn only file name(s) that contains match
file pattern /WINDOW=5more -5 +/pattern fileDisplay search line plus two lines before and after. (Terminate with q).
file pattern /WIND=(5,0)cat file | more -5+patternDisplay search line plus next five lines.
SET DEFAULTcdChange directory.
SET FILE/OWNERchgrpChange group ownership of a file.
SET HOSTrloginNetwork login to trusted host.
SET HOST /DTEtipDial remote host.
SET HOST 0 /LOGscriptRecord a transcript of a terminal session.
SET PASSWORDpasswdChange you local password.
SET PROCESS /PRIORITYnice
renice
Change the priority of a process.
SET PROTECTIONchmod Change file protection.
/DEFAULTumaskChange default protection for files not yet created.
SET TERMINALtset
stty
Set terminal characteristics.
SET VERIFYksh -x
csh -x
Verify command or script execution. Echo after variable substitution.
SHOW DEFAULTpwdDisplay current directory.
SHOW DEVICE /FULLdf filesystemDisplay information on a file system
SHOW LOGICALprintenvDisplay environment characteristics.
SHOW PROCESS /ALLps -lDislay all processes on system.
SHOW /QUEUElpqDisplay default print queue status.
SHOW STATUStimeDisplay resources used by a process.
SHOW TIME dateDisplay date and time
SHOW USERSwhoDisplay the list of current system users.
SORTsortSort and merge.
/KEYsort +fskip.cskip
sort -fskip.cskip
Starting/ending porint of sort key.
/OUTPUTsort -o fileDirect output to file.
SPAWN /NOWAITbgMove a process to the background.
STOP /IDkill -9Remove a process.
SUBMIT atStart a process at a latter time.
TYPEcatDisplay a file
/PAGEmoreDisplay a file, pausing after each page.
/PAGE NL:clearClear the terminal screen.
WRITEecho var > fileCreate a file and write a string or the contents of a variable to it.
WRITEecho var >> fileAppend a string or the contents of a variable to an existing file.
WRITE SYS$OUTPUTecho (c Shell)
print (Korn)
Write to standard output.
Of course it is possible to have a bash shell on OpenVMS. That requires the installation of GNV (open source project at SourceForge).

2012/11/22

OpenVMS numbers

Here are some numbers I collected over the years using OpenVMS.

Command Line Interpreter (CLI)

Description
number
number of characters in verbs and qualifiers examined by CLI (keywords read in entirety)
4
minimum abbreviation permitted for verbs and qualifiers, assuming truncation is unique.
Exceptions: CONTINUE, DEPOSIT, EXAMINE and RUN can be truncated to 1 character eventhough the truncation is not unique.
1

Command Procedures (DCL Scripts)

Description
number
maximum number of parameters which can be passed to a command procedure or a subroutine
8
(P1..P8)
maximum depth of nested command procedures (including the top-level procedure)
32

Command String

Description
number
maximum number of characters after symbol and lexical expansion
1024
maximum number of characters permitted without using hyphen '-' for command string extension
256
maximum number of characters permitted per element
255
maximum number of elements permitted
128

File Specifications

Description
number
maximum length for full file specification, including delimiters
255
maximum length of a (DECnet) node name
6
maximum length of the optional access control string used with node name
42
maximum length of a device name, including controller and unit number
15
maximum length of a filename
39
minimum length of a filename
0
maximum length of a file type, excluding '.'
39
minimum length of a file type
0
maximum version number
32767
maximum length of a directory name
39

Forms

Description
number
maximum length of a form name
31
range of permissible form numbers
0..999
maximum length of a form description
255
range of permissible form length values
1..255
maximum length of a stock name
31
range of permissible form width values
1..65535

Label Names

Description
number
maximum length
255

Logical Names

Description
number
maximum length of a logical name
255
maximum length of a logical table name entered in LNM$PROCESS_DIRECTORY or LNM$SYSTEM_DIRECTORY
31
maximum length of a logical node name
15

Passwords

Description
number
maximum length of a password
31

PRINT (see also Queues)

Description
number
range of allowable values to /COPIES qualifier
1..255
range of allowable values to /JOB_COUNT qualifier
1..255
maximum length for /NAME qualifier
39
maximum length for /NOTE qualifier
255
maximum length for /OPERATOR qualifier
255

Process Names

Description
number
maximum length of a process name
15

Prompt

Description
number
maximum length of a prompt string
32

Process Names

Description
number
maximum length of a process name
15

Queues

Description
number
range of process priorities for /BASE_PRIORITY qualifier
0..15
maximum length of a queue name
31
maximum number of concurrent jobs per queue (/JOB_LIMIT qualifier)
255
maximum number of parameters in the /PARAMETER qualifier
8
maximum length for each parameter in the /PARAMETER qualifier
255
maximum length for all parameters combined
480
range of values for the /PRIORITY qualifier
0..255
range of pages that can be printed with START/QUEUE/ALIGN
1..20
maximum length permitted in the START/QUEUE/SEARCH string
63
range of buffers permissible with START/QUEUE/MANAGER/BUFFERS
63
range of blocks permissible with START/QUEUE/MANAGER/EXTEND_QUANTITY
10..65535

RECALL

Description
number
range of permissible RECALL command specifiers
1..20
size of the RECALL buffer (in characters)
1025
maximum length read from a RECALL command
255

REPLY/REQUEST

Description
number
maximum length of the message text (in characters)
128

Symbols

Description
number
maximum length of a symbol name
255
minimum length of a symbol name
1
maximum length of an evaluated string expression in a symbol assignment
1024
range of permissible integers in substring replacement (symbol[x,y] := string where x+y <= 769)
0..768
maximum length of an arithmetic overlay
32
maximum length of an evaluated string expression without /SYMBOL qualifier on the WRITE command
1024
maximum length of an evaluated string expression with /SYMBOL qualifier on the WRITE command
2048

UIC

Description
number
numeric group number range (octal)
0..37776
numeric member number range (octal)
0..177776
maximum length of a group name (in named format)
31
maximum length of a member name (in named format)
31

Volume Names

Description
number
maximum length of a disk volume name
12
maximum length of a tape volume name
6
alternate maximum length of an ANSI-labelled magnetic tape
(14 for owner identifier field, 1 for volume accessibility field)
15