2015/05/21

Playing with the PIPE command

If you want to do something with het output of e.g. the SEARCH command, without creating intermediate files, you can use the PIPE command. One way to do this, is using 2 scripts, but it requires the second script to check the existance of SYS$PIPE.

The scripts below do nothing useful, but are just for demonstration.

DO_SOMETHING.COM

$ IF P1 .EQS. ""
$ THEN
$     WRITE SYS$OUTPUT "NO PARAMETER"
$ ELSE
$     PIPE DIR /SIZE/DATE/OWNER | -
           SEARCH SYS$PIPE 'P1' | -
           @DO_SOME_MORE | -
           TYPE SYS$PIPE > SOME_OUTPUT.TXT
$ ENDIF
$ EXIT

DO_SOME_MORE.COM

$ IF F$TRNLNM( "SYS$PIPE" ) .EQS. "" 
$ THEN
$     WRITE SYS$OUTPUT "NO PIPE"
$ ELSE
$read_loop:
$     READ /END=end_loop /ERROR=end_loop SYS$PIPE input_line
$     WRITE SYS$OUTPUT F$ELEMENT( 0, ";", input_line )
$     GOTO read_loop
$end_loop:
$ ENDIF
$ EXIT

You can do this with just one DCL script, which contains a PIPE command, but runs itself again within the PIPE command to process the output of a previous command.


DO_SOMETHING.COM

$ IF P1 .EQS. ""
$ THEN
$     WRITE SYS$OUTPUT "NO PARAMETER"
$     EXIT
$ ENDIF
$ IF P1 .EQS. "CALL$SELF"
$ THEN
$     CALL do_some_more
$ ELSE
$     do_some_more := @'F$ENVIRONMENT( "PROCEDURE" )' "CALL$SELF"
$     PIPE DIR /SIZE/DATE/OWNER | -
           SEARCH SYS$PIPE 'P1' | -
           do_some_more | -
           TYPE SYS$PIPE > SOME_OUTPUT.TXT
$ ENDIF
$ EXIT
$do_some_more: SUBROUTINE
$read_loop:
$     READ /END=end_loop /ERROR=end_loop SYS$PIPE input_line
$     WRITE SYS$OUTPUT F$ELEMENT( 0, ";", input_line )
$     GOTO read_loop
$end_loop:
$ ENDSUBROUTINE

2015/03/23

Tracing using SDA

The problem

About one or two weeks ago, I needed to find a problem in virtual memory allocation/de-allocation, since a process was running out of virtual memory. In our system we already had some tracing in a library in place, using conditional compilation. However, when building the entire system the trace just gave too much data.

The solution

I stumbled upon an article at http://labs.hoffmanlabs.com about the C-macro tr_print. That was just what I was looking for.

The definition of the macro can be found by issueing the following command

$ libr/text sys$library:sys$lib_c.tlb /extract=vms_macros /output=tt:

Note: I used output to tt:, which is effectively my terminal, so I do not extract to a file, but straight to the screen. The last part of the file shows the definition of C-macro tr_print, which was the only thing I was interested in.

Since we code in HP Pascal, at first I tried to write code like is included in the tr_print macro, but that did not quite work out. Some issues with parameter passing, I guess. Not spending too much time on getting it to work, I decided to create a small C file with a function taking only one string parameter, and to call the C function from a Pascal module.

The source code

The created C file looks like this (stripped from all mandatory style elements):

writetrc_c.c

#include <vms_macros.h>
#include <stdlib.h>

void _write_trc_c( const char *trace_string )
{

    /* NOTE: THE DOUBLE PARENTHESES ARE REQUIRED IN THIS MACRO BY DESIGN */

    tr_print(( trace_string ));

}

and the pascal module looks like this:

writetrc.pas

[
    ENVIRONMENT
    (
        'writetrc.pen'
    )
]

MODULE writetrc;

[GLOBAL,ASYNCHRONOUS]
PROCEDURE write_trc(
    p_trace_string : VARYING [$m1] OF CHAR
);

{----- External Routine Declarations ------}

[EXTERNAL]
PROCEDURE _write_trc_c(
    p_trace_str : [IMMEDIATE] C_STR_T
); EXTERNAL;

{---------- Variable Declarations ---------}
VAR
    lv_trace_string     : [VOLATILE] STRING($m1 + 1); 
                          { volatile to get rid of compiler warning }
    lv_trace_str_ptr    : C_STR_T := NIL;

BEGIN

    { Calling a C routine, so zero terminated string required }

    lv_trace_string := p_trace_string + CHR(0);
    lv_trace_str_ptr := C_STR( lv_trace_string );

    { C-function checks if the trace is activated   }
    { If not, it immediately returns                }

    _write_trc_c( lv_trace_str_ptr );

END; { of PROCEDURE write_trc }

END.

Compilation

Compilation of the C source is done as follows:

$ define DECC$TEXT_LIBRARY SYS$LIBRARY:SYS$LIB_C.TLB
$ cc writetrc_c.c /debug /noopt

Logical DECC$TEXT_LIBRARY needs to be set to let the C compiler find vms_macros.h.
Compilation of the Pascal source is done as follows:

$ pas writetrc /debug /noopt

Note: for development and test, we standard compile with /debug /noopt

Linking

When linking a program that uses the functions above, you must include /SYSEXE. The link command will then look like:

$ link example writetrc.opt/opt /sysexe

Where the file writetrc.opt contains the following 2 lines:

writetrc_c.obj
writetrc.obj

Example program

Just to demonstrate, here is a small example program, that writes "Hello, World! 2015" to screen and in the trace buffer.

[
    INHERIT
    (
        'writetrc.pen'
    )
]
PROGRAM example( INPUT, OUTPUT );

VAR
    i : INTEGER;
    s : STRING(40);
BEGIN
    i := 2015;
    s := 'Hello, World!';
    writetrc( s + DEC(i) );
    WRITELN( s, ' ', i );
END.

Compile as usual and link as described earlier.

Running the example

Open a second terminal to start SDA with the correct privileges. You need at least privilege ALTPRI to start the trace, and another privilege to increase the buffer size. Since I don't know yet which one, I use priv=all for now.

$ set proc /priv=all
$ analyze/system
SDA> TR LOAD
SDA> TR START TRACE ! optionally with /BUFFER=<nr of pages>
SDA>

Go back to the other terminal and run the example:

$ run example
Hello, World! 2015
$

Go back to the system analyzer session.

SDA> TR STOP TRACE
SDA> TR SHOW TRACE

You should get a screen with a header, and one trace line with timestamp and text "Hello, World!  00002015"  (slightly different formatted than the output of the WRITELN statement).

Finally, exit the system analyzer with:

SDA> TR UNLOAD
SDA> EXIT

That's all, folks!

2014/11/25

Date and Time

Recently we had a discussion at work about unique file names. OpenVMS has facilities for that, like the lexical F$UNIQUE in DCL and tmpnam in the C Runtime Library. However, people tend to write their own functions for this. No problem of course. One of the solutions in DCL is e.g. taking a combination of the PID and date/time. I might spend a post on that later, but you might find some implementations on Google.

We talked about the OpenVMS Date/Time, and the time base used in OpenVMS: November 17, 1858. Then someone wanted to know what was so special about that date, and if  issues were to be expected on OpenVMS with date/time.

Kevin G. Barkes describes it in  DCL Dialogue Online 199111:
The short story is the Smithsonian Astrophysical Observatory adopted the Modified Julian Day (not related to the Julian calendar) in 1957 for satellite tracking purposes. January 1, 1957 was Julian day 2,435,839. The 8K, non-virtual 36-bit IBM computer used by the SAO kept the Julian day in the left 18 bits of a 36-bit word, and the hours and minutes in the right 18 bits of a word. The problem was the octal representation of Julian day 2,435,839 would have required 22 bits, wasting 14 bits of precious memory.

So, the SAO decided to settle on using 18 bits to represent what was called the Modified Julian Day. From November 17, 1858, this permitted 700 years of timekeeping. Using 17 bits allowed 300 years, plus one bit to allow for representing negative time. No star  catalog used by SAO was older than 1858, so 11/17/1858 was picked as the starting date.

There is also a pretty detailed article on OpenVMS Ask The Wizard.

The Modified Julian Day allows OpenVMS to handle dates through a little before three in the morning on July 31, 31086. That's when the 63-bit absolute time representation within VMS goes negative and all VMS time operations halt (Source: DCL Dialogue Online 199111).
That does not mean that there were/are no other issues with date/time on OpenVMS. These are the ones I know of:

There was the 10,000 day limit in LIB$CVT_TO_INTERNAL_TIME causes problems for DECthreads since it is using this routine to convert Unix times to VAX time. It will fail to work on 19-May-1997. I had problems with this one in 1997, when running the OSU HTTP Server. The VAXStation 4000 running the HTTP server would become very slow when the HTTP Server was running, since it relies on DECthreads. After installation of the patch, the problem disappeared.

Issues regarding Y2K have been dealt with in the Year 2000 response (Source: OpenVMS Y2K FAQ).

The first possible problems with date/time on OpenVMS can be expected in 2038. In 2038 problems can occur with the C time_t structure. OpenVMS dealt with this problem in 1998, in the Year 2000 response, postponing the issue to 2106 (Source: OpenVMS Year 2038). That still leaves at least 24 years to fix applications. Recompiling on the current OpenVMS release will give time to 2106 to solve this problem. So we are safe for another 92 years.

The next problem will occur December 10, 5941. Someone reported a bug on DSNlink in the F$CVTIME() DCL lexical function and the LIB$DAY_OF_WEEK RTL routine. The functions will report the wrong day of the week, due to a problem in the time calculation algorithm. The routine counts the number of 100 nanosecond intervals from midnight on 11/17/1858, which is stored in a 64-bit quadword. This number is divided by 600 million to convert it to minutes, and the result is stored in a longword value. From that date to 12/10/5941 is 7FFFFF80 (hex) minutes, only a little over two hours away from a longword integer overflow error. Fortunately, the bug has been reported to VMS Engineering (Source: DCL Dialogue Online 199111). I have no clue if this has been fixed already, but I might not be around to encounter the bug anyway.

Another minor problem is the fact that all of OpenVMS' time-related displays and routines can only display four digits in the year field, but the maximum year OpenVMS can handle is 31086. There is still time to fix this :-) before 31-DEC-9999 (Source: DCL Dialogue Online 199111). Maybe VMS Software Inc. will do so.

As you can see, if the issues are resolved in time, OpenVMS can run at least another 29072 years.

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