OpenVMS Porting Library Release Notes September 2003 Introduction New Features in A9 Kit New Features in Previous Kits Bug Fixes in A9 Kit Bug Fixes in Previous Kits Contents of the Kit Building the Porting Library Software Prerequisites Expanding and Installing the Source Kit Installing the Binary Run-Time Kit (Alpha systems only) Files Built by the Library Logical Name Prefix Building the Code Build Options Building the Application Defines VMS_JACKETS.H Include Path Linking Running the Application Logical Names Files and Routines Header Files C/C++ Code Other Files Introduction --------------------------------------- The OpenVMS Porting Library is designed to address some of the more common porting issues that occur when you port C/C++ applications from Unix to OpenVMS. However, it will not solve all the problems you may encounter. Note that the code in the Porting Library is not always completely functional and will not work in all of the situations in which you try to use it. The code was written to solve specific problems while porting specific products. The code usually does "just enough." OpenVMS is continually improving and evolving the C RTL. Some functions that were missing two or three years ago are available in more recent versions of the C RTL. This eliminates the need for some of the routines in the Porting Library. Whenever possible, use the C RTL version of a routine, because this is likely to be a more complete implementation (and is supported). Benefits of the Porting Library --------------------------------------- Porting C/C++ applications from Unix to OpenVMS requires quite a bit of repetitive work, because many of the changes you need to make are common across several applications. The Porting Library captures some of these frequently made changes and includes them in a library that can be reused. This allows additional applications to be ported more quickly and easily. Functionality Provided --------------------------------------- Some of the major functionality provided by the Porting Library is as follows: File name parsing and conversion of filenames into routines such as open and stat. This allows otherwise invalid names to be accepted (for example, long names or names of the form a.b.c). A poll function that can accept event flags as well as sockets. This makes it easy to integrate X events into poll/select code. A socket pair implementation. A getpwent, setpwent, and endpwent implementation. Enhancements to opendir (and related routines) to allow opendir("/") to return a list of all disk devices on the system. Easy tracing of all files being opened. Easy tracing of all dlsym operations. Products Ported Using the OpenVMS Porting Library Versions of the OpenVMS Porting Library were used to port the following products to OpenVMS: Mozilla for OpenVMS Alpha Software Development Kit (SDK) for the OpenVMS Operating System, for the Java™ Platform Netscape FastTrack Web Server for OpenVMS Netscape Commerce and Communications Web Servers for OpenVMS Navigator V3.x for OpenVMS New Features in A9 Kit --------------------------------------- The following new features are included in the A9 kit, released September 2003. None. The A9 kit includes a bug fix only. New Features in Previous Kits --------------------------------------- The following new features were included in the A1 through A8 kits, and have been rolled into the A9 kit. Made source code changes for Itanium (IA64) support. Added GENERIC_VMS_Filename_parser to symbol vector. A binary run-time kit (PCSI file) of the OpenVMS Porting Library is now available for download. See Installing the Binary Run-Time Kit (Alpha systems only) for more information. Make rename jacket handle directory names contain a period. Add XextAddDisplay to GENERIC_MOTIF_REDEFINES.H. Added rudimentary symlink support. creat, open, and fopen jackets now use optional arguments on the actual CRTL calls. These arguments are derived from logical names and allow you to have different arguments for different file types. (The open jacket contains more information.) If you need the previous default behavior, define the following logical name: $ define VMS_OPEN_ARGS_1 " ", - "shr=get,put", "rfm=stmlf", "deq=500", "fop=dfw,tef" Added GENERIC_OPEN_NOSHR_JACKET - same as regular open jacket, but forces no sharing. Added XGetClassHint to MOTIF_REDEFINES utime would fail to set the revision date if it were earlier than the file's creation date. Now if the revision date is earlier than the creation date, the creation date is also set to the specified date. Define ON_RUBY to build on a OpenVMS Alpha Version 7.3-1 system. This is only for building the jackets on a V7.3-1 system. The run-time will still not call RUBY functions such as symlink. Define RUBY_RTL to cause the jackets to call some of the routines which are available in OpenVMS Alpha Version 7.3-1. Currently only symlink and readlink will be called. Add SYS$SHARE:PTHREAD$RTL to the MAKE_OPTIONS.COM command file. Define re_comp and re_exec to their uppercase equivalents. Add RE_COMP and RE_EXEC to make_options.dat Only perform lstat or localtime_r redefines in vms_jackets.h if __CRTL_VER < 70301000 Remove siginfo_t as OpenVMS does not support this and our implementation is incomplete. In the poll code, ignore an fd of -1 because some UNIX code uses this to signify an invalid fd (one which should be ignored). grp.h gets a few more definitions and a fake-out for getgrnam. dlopen jacket now performs the standard jacket filename parsing on the library name (this allows Mozilla plugins to be located in $HOME/_mozilla/plugins). Revised the previous open jacket truncate mode fix to actually delete the file before opening it. In the open jacket, force the record format to be stmlf on all new files. Defining prefix_FILE_OPEN_TRACE causes each open()/fopen() call to print out the name of the file being opened along with the flags and mode (open) or a_mode (fopen). Defining prefix_BREAK_ON_OPEN to string will cause an open()/fopen() call to break in the debugger if the name of the file being opened contains the string string (debug builds only). Added prefix_GETCHAR routine, which always reads from the terminal even if input is coming from a command file. Added prefix_GETCHAR_NOECHO, which is the same as prefix_GETCHAR, except that the character is not echoed to the screen. Added debug support in poll jacket. Added support in poll() for exponential sliding poll timer and changed poll timer defaults. Minor performance improvements in poll jacket. Initial limited support for ConnectionNumber. Initial support for select() jacket. Modified open jacket to add performance enhancements to each open call (DEQ=500, FOP=DFW,TEF). Modified open jacket so that files opened in truncate mode overwrite any existing version of the file (feature can be turned off). The stat() call now returns a sensible protection (O:RWED,G:RE,W:E) on device root directories. Added a symlink(), which returns -1. The setlocale() call now maps to the DECwindows setlocale routine (__XSETLOCALE) which returns a UNIX style locale string. (To use this, you will need to link against sys$share:decw$xlibshr.) Added regex support (GNU regex routines). The open() and creat() calls now check for -1/EVMSERR/RMS$_SYN and convert it to -1/ENOENT. If mkdir("/xxx") fails with -1/EINVAL, it will retry with "/xxx/000000". New header files regex.h syslog.h New C/C++ files regex.c symlink.c x_support.c Bug Fixes in A9 Kit --------------------------------------- The following bug fix is included in the A9 kit. Made fix to open_jacket to handle case where open() is called with O_TRUNC but not O_CREAT. Bug Fixes in Previous Kits --------------------------------------- The following bug fixes were included in the A1 through A8 kits. Made fix to open_jacket to handle case where open() is called with O_TRUNC but not O_CREAT. In LINK_OPTIONS.COM, link against the PTHREAD$RTL in SYS$LIBRARY, not SYS$SHARE. Make lstat jacket call our stat jacket, not the real stat routine. Removed #pragma __standard from end of grp.h. Minor ".." fix to generic_tidy_spec in utils.c. Fixed the access() problem that caused the Mozilla for OpenVMS download problem ('You have chosen to download a file of type: "#1" [#2] from'). Removed two asserts from poll jacket, because they were causing the opccus crashes. Fixed a problem where the count returned from select() was interpreted incorrectly. The MOTIF_REDEFINES.H header file now handles XtRegisterDrawable and XtUnregisterDrawable correctly. Corrected file system_parsing.c for file names greater than 39 characters. The access() call now returns success when passed the root ("/") directory. Previously it would fail. Corrected mmap prototype so it works on OpenVMS Version 7.2 and later systems (involves defining __CRTL_VER). Contents of the OpenVMS Porting Library --------------------------------------- Included in the Porting Library The OpenVMS Porting Library consists of the following: Jacket routines for many of the C RTL functions (for example, creat, open, rmdir). Each jacket routine performs some additional work before calling the real C RTL function. Routines to supplement the C RTL (for example, socketpair, writev). Header file to perform PTHREAD redefines (solves casing problem when compiling with /NAMES=AS_IS). Header file to perform MOTIF redefines (solves casing problem when compiling with /NAMES=AS_IS). Header files that are not usually shipped on OpenVMS (for example, poll.h). Makefile to build on OpenVMS. gmake (3.76.1) image pre-built for OpenVMS Alpha Version 7.1 and OpenVMS VAX Version 7.1. Not Included in the Porting Library The following functionality is not included: A method to automatically include the main header file (VMS_JACKETS.H) into each compilation (although some ideas are offered). Java and JavsScript redefines. These are version dependent. Building the Porting Library --------------------------------------- This section explains how to build the Porting Library. Software Prerequisites --------------------------------------- The OpenVMS Porting Library requires the following software: OpenVMS Alpha or OpenVMS VAX Version 7.1 (or later) DEC C Version 6.2 (or later) The Porting Library code is intended to be built on OpenVMS Version 7.1 or later. It will run on the version of OpenVMS on which is was built or any later version. Earlier versions of OpenVMS and DEC C have not been tested. Expanding and Installing the Source Kit --------------------------------------- Alpha and VAX versions of the self-extracting archive are available for download. This is the full source kit. If you are installing the OpenVMS Porting Library for the first time, or if you are upgrading from a previous kit, you should install the full source kit. The source kit is intended for developers who want to use the OpenVMS Porting Library in their own applications. After you install the source kit (by expanding the file), you can build the OpenVMS Porting Library and use the jacket routines in your application. Download the appropriate source kit (Alpha or VAX), then create a directory where you want the source code tree to reside. Set your default directory to that location. To expand and install the OpenVMS Porting Library self-extracting archive, run the Alpha or VAX kit you downloaded. For example: $ CREATE/DIRECTORY DKA0:[PORTING] $ SET DEFAULT DKA0:[PORTING] $ RUN DKA0:[KITS]PORTING-A7.SFX_AXPEXE Installing the Binary Run-Time Kit (Alpha systems only) --------------------------------------- Begining with the A7 kit, a PCSI file of the binary run-time kit for Alpha systems is also available for download. The run-time kit is intended for those users who are running an application that requires the OpenVMS Porting Library (such as Mozilla for OpenVMS, Secure Web Browser for OpenVMS, and GTK+ for OpenVMS). Occasionally a bug in one of these applications may be caused by a bug in the OpenVMS Porting Library, or a problem in one of these applications may be corrected by a new feature added to the OpenVMS Porting Library. In that case, downloading and installing the OpenVMS Porting Library PCSI file (rather than the source kit) is all that is required. Note that the OpenVMS Porting Library PCSI kit is automatically installed when you install Mozilla for OpenVMS and the Secure Web Browser. To install the OpenVMS Porting Library run-time kit on an Alpha system, enter the following command: $ SET DEFAULT DKA0:[PORTING] $ PRODUCT INSTALL OPL Files Built by the Library --------------------------------------- After you expand the OpenVMS Porting Library kit, you must build the library. When you run the Makefile, the following files are built: VMS_JACKETS.EXE Shareable image. Define NOSHR to prevent the shareable image from being built. VMS_JACKETS.OLB Object library. Define NOLIB to prevent the object library from being built. VMS_JACKETS.A A second version of the object library, with a filetype of .A instead of .OLB. This is for use within POSIX. Define NOPOSIX to prevent the POSIX object library from being built. Logical Name Prefix Any logical names used in the code will use "VMS_" as a prefix. You can override this default by defining VMS_PREFIX. See Build Options for more information. Building the Code --------------------------------------- Perform the following steps to build the OpenVMS Porting Library code. Define a symbol to invoke gmake. For example, the symbol on Alpha is similar to the following: $ gmake == "$DKA0:[PORTING]make_3_76_1_vms_alpha" Use the gmake command, specifying any required options on the command line. Note that quotation marks are needed around any options. For example: $ gmake ! builds the library optimized (no debug) $ gmake "DEBUG=1" "VAX=1" ! VAX debug build Afer you build the Porting Library, you must install it. Again use gmake: $ gmake "DIST_TOP=DKA0:[PORTING.DIST.]" install This command moves the files you need to build with the Porting Library to the DKA0:[PORTING.DIST] directory tree. It is this [PORTING.DIST.INCLUDE] directory that you need to specify in the include path when you build the library. Build Options --------------------------------------- DEBUG - Compile with /DEBUG /NOOPTIMIZE. Link with /DEBUG. DIST_TOP - Specifies where the Porting Library files should be installed. Note that the directory specification must have a trailing period. If the value contains any dollar sign characters, then you must preceed each dollar sign with another dollar sign. NOLIB - Do not build the object library LIBVMS.OLB. NOPOSIX - Do not build the POSIX object library LIBVMS.A. (LIBVMS.A is a copy of LIBVMS.OLB for use with POSIX). NOSHR - Do not build the shared library LIBVMS.EXE. ON_RUBY - Use if you are building on an OpenVMS Alpha Version 7.3-1 (or later) system. This is only for building the jackets on a V7.3-1 (or later) system; the run-time will not call functions which are new to V7.3-1, such as symlink. RUBY_RTL - Causes the jackets, at run-time, to call some of the functions which are new to OpenVMS Alpha Version 7.3-1. Currently only symlink and readlink fall into this category. VMS_PREFIX=name - Use name as a prefix for logical names. Some of the jackets contain features that are enabled or disabled by logical names. By default all such logical names are prefixed with "VMS_", but you can change this by using the VMS_PREFIX option. VMS_PREFIX is also used to determine the names of the library and sharable image produced. WITH_UNEXPECTED - Compile a routine named unexpected. This is a workaround for an old problem with the C++ compiler. VAX - Build is being done on a VAX system (default is Alpha). Building the Application --------------------------------------- This section explains how to integrate your application with the Porting Library. It assumes that you have already built and installed the Porting Library as described in Building the Code. Defines --------------------------------------- If you compile your application with the /NAMES=AS_IS compiler option, consider defining these on your compiler command line: GENERIC_MOTIF_REDEFINES - Forces extra include file(s) to be included that handle the casing problems in MOTIF. GENERIC_PTHREAD_REDEFINES - Forces extra include file(s) to be included that handle the casing problems in PTHREADS. VMS_JACKETS.H You must include VMS_JACKETS.H as the first include file of every module. The following methods will achieve this result. Edit every file and add the following line to the top of the file: #include "VMS_JACKETS.H" This can be time-consuming for a large number of files. Use a shortcut similar to the following: Define the cc command to invoke a command file (or script if you are building in POSIX). For this example, assume that the command file is passed the file foo.c to compile. The command file creates another file (with a different name in the same directory or the same name in a mirror directory) called fake_foo.c, that contains two lines: #include "VMS_JACKETS.H" #include "foo.c" The command file compiles fake_foo.c, creating foo.obj. If you are using make (or similar) to build your application, you can change the rule for compiling C (and C++) code to the following. (Note that this example is simply demonstrating the principle and will not work as is.) $(CC) $(CFLAGS) /OBJ=$@ DIST:VMS_JACKETS.H+$< If you are using GNV, use the -include option. (If you are porting UNIX code to OpenVMS, be sure to see http://gnv.sourceforge.net.) Include Path --------------------------------------- Make sure that the include path contains the [PORTING.DIST.INCLUDE] directory, which is the directory where VMS_JACKETS.H is located. This directory was created and populated when you ran gmake install. Note that there are other include files in subdirectories such as rpc and sys, so be very careful if you move VMS_JACKETS.H. Linking --------------------------------------- Once you've compiled your code with VMS_JACKETS.H in each module, you need to link your code. Select either the object library or the shareable image; both contain the same routines, and both are placed in the [PORTING.DIST.LIB] directory by gmake install. If you link against the shareable image, there is a linker options file in [PORTING.DIST.LIB] for this purpose. Running the Application --------------------------------------- Once you have successfully built your application, you are ready to run it. This section contains information that you need to be aware of when you run your application. Logical Names --------------------------------------- The following logical names may need to be defined in order for your application to run after you have built it with the OpenVMS Porting Library. The default logical name prefix is "VMS_". You can change this when you build the Porting Library. See Build Options for more information. VMS_BREAK_ON_OPEN Used in OPEN_JACKET.C and FOPEN_JACKET.C When defined to string, causes an open()/fopen() call to break in the debugger if the name of the file being opened contains the string string (debug builds only). VMS_DEBUG_STAT Used in STAT_JACKET.C If defined, enables logging code in the stat routines. The default is off, and the logging code is only built in DEBUG versions of the Porting Library. VMS_FILENAME_CONTROLS Used in FILESYSTEM_PARSING.C Allows you to control many aspects of how filenames are parsed before they are handed to routines such as open and stat. For more information, see SYS$SYSROOT:[SYSHLP.JAVA]JAVA$FILENAME_CONTROLS.COM on any Alpha Version 7.1 or later system. This is the same code that is used by Java. VMS_FILE_OPEN_MODE Used in OPEN_JACKET.C Affects how a file is opened. The default is to always use "shr=get,put". Other modes are available. Usually the open jacket routine will call umask before opening a file in order to get the requested protection set correctly. The umask call can be disabled by adding 10 to the value of this logical. VMS_FILE_OPEN_TRACE Used in OPEN_JACKET.C and FOPEN_JACKET.C When defined, causes each open()/fopen() call to print out the name of the file being opened along with the flags and mode (open) or a_mode (fopen). VMS_NULL_DL_NAME Used in DL.C The name of the shareable image to be loaded when dlopen is passed NULL as the file name. There is no default. If you want to specify a value so that dlopen(NULL,mode) will succeed, use something similar to SYS$SHARE:CMA$TIS_SHR.EXE or SYS$SHARE:DECC$CRTL.EXE (or any image that you know will always be loaded for your application). VMS_OPEN_ARGS_xx Allows you to specify additional open arguments based on the file type being opened. Refer to OPEN_JACKET.C for full details on how to use these logicals. VMS_POLL_TIMER_MIN VMS_POLL_TIMER_MAX VMS_POLL_TIMER_DELTA Used in POLL_JACKET.C In order to support event flags in the poll code, the code has to periodically check the event flags to see if any are set. These logicals control the frequency at which the flags are checked. The defaults are: VMS_POLL_TIMER_MIN = 10 millisecs VMS_POLL_TIMER_DELTA = 1 millisecs VMS_POLL_TIMER_MAX = 200 millisecs The poll timer is a sliding timer. It begins at VMS_POLL_TIMER_MIN, and increases by VMS_POLL_TIMER_DELTA for each poll operation. The timer is never allowed to exceed VMS_POLL_TIMER_MAX. As soon as any activity is seen, the timer resets to the start value. A delta value of zero means that the timer should be doubled each time there is no activity detected. VMS_STAT_DEVICE_ROOTS Used in OPENDIR_JACKET.C Usually the Porting Library's stat code will not stat a device root directory ([000000]) because performing a stat on certain device roots can be very slow. (For example, an infoserved device can take 15-20 seconds to respond.) The information returned can usually be guessed. Define this logical (to any value) if you wish root directories to be stat'd. The default is off. VMS_TRACE_FILENAMES Used in VMS_JACKETS.H and many C files. Many of the jacket routines such as open, stat, and dlsym have tracing functionality. This is very useful. The default is off. To enable tracing, define VMS_TRACE_FILENAMES to any value. Files and Routines --------------------------------------- The naming convention is as follows: Files --------------------------------------- Files containing new functionality have the name of the function, for example fchmod.c. Files containing jacketed functionality have the name of the function and the "_jacket" appendix, for example \chdir_jacket.c. Routines --------------------------------------- A routine that does not exist in the C RTL is named GENERIC_ROUTINE, where ROUTINE is the uppercased C function name. A prefix is used to make it obvious that it is not a genuine C RTL function. A routine that exists in the C RTL and is being jacketed is named GENERIC_ROUTINE_JACKET, where ROUTINE is the name of the C function that is being jacketed. Header Files --------------------------------------- Following are the header files included in the OpenVMS Porting Library. Some header files are referenced by the main VMS_JACKETS.H header file, while others are listed because UNIX code requires them. Header File Description --------------------------------------- dlfcn.h Protos and constants for dll routines contained in dl.c. endian.h Defines a few of the common endian items. gen64def.h Defines _generic_64 struct. grp.h Empty file. Present for compilers. malloc.h According to the Single UNIX Specification, there is no such header file. However, we have found some code that includes it. This version includes stdlib.h which is where you find malloc and others. motif_redefines.h X redefines. Only needed if compiling AS_IS. poll.h Accompanies the poll_jacket.c code. pthread_redefines.h Pthread redefines. Only needed if compiling AS_IS. syslog.h Defines some system items. regex.h Standard GNU regex header file for regex (regular expression) support termios.h Standard UNIX version. utime.h Standard UNIX version. vms_jackets.h Main include file. Must be included by all your C/C++ code. rpc/types.h Empty file. Present for compilers. rpc/xdr.h Empty file. Present for compilers. sys/param.h Empty file. Present for compilers. sys/select.h Empty file. Present for compilers. sys/statfs.h Accompanies the statfs.c code. sys/un.h Empty file. Present for compilers. C/C++ Code --------------------------------------- Source File Routines --------------------------------------- access_jacket.c GENERIC_access_Jacket chdir_jacket.c GENERIC_chdir_Jacket chmod_jacket.c GENERIC_chmod_Jacket chown_jacket.c GENERIC_chown_Jacket creat_jacket.c GENERIC_creat_Jacket delete_jacket.c GENERIC_delete_Jacket dl.c GENERIC_dlclose GENERIC_dlerror GENERIC_dlopen GENERIC_dlsym fchmod.c GENERIC_fchmod fcntl.c GENERIC_fcntl filesystem_parsing.c GENERIC_VMS_Filename_parser Plus some support routines fopen_jacket.c GENERIC_fopen_Jacket fread_jacket.c GENERIC_fread_Jacket fstat_jacket.c GENERIC_fstat_Jacket getpwent.c GENERIC_endpwent GENERIC_getpwent GENERIC_setpwent getpwnam_jacket.c GENERIC_getpwnam_Jacket getpwuid_jacket.c GENERIC_getpwuid_Jacket getcwd_jacket.c GENERIC_getcwd_Jacket is_image.c GENERIC_is_image lockf.c GENERIC_lockf lstat.c GENERIC_lstat mkdir_jacket.c GENERIC_mkdir_Jacket mmap_jacket.c GENERIC_mmap_Jacket GENERIC_mmap_Jacket8 GENERIC_munmap_Jacket noecho.c GENERIC_noecho opendir_jacket.c GENERIC_opendir_Jacket GENERIC_readdir_Jacket GENERIC_closedir_Jacket GENERIC_rewinddir_Jacket GENERIC_seekdir_Jacket open_jacket.c GENERIC_open_Jacket GENERIC_open_shared_Jacket GENERIC_open_java_Jacket GENERIC_open_noshr_jacket poll_jacket.c GENERIC_poll privs.c GENERIC_remove_image_privs GENERIC_set_privs GENERIC_restore_privs pthread_routines.c GENERIC_pthread_attr_getscope GENERIC_pthread_attr_setscope readlink.c GENERIC_READLINK realpath.c GENERIC_realpath recv.c GENERIC_RECV regex.c regexec, regcomp, regerror, regfree, and other support routines remove_jacket.c GENERIC_remove_Jacket rename_jacket.c GENERIC_rename_Jacket rmdir_jacket.c GENERIC_rmdir_Jacket send.c GENERIC_SEND setsid.c GENERIC_setsid share_file_support.c GENERIC_File_Share_INIT GENERIC_File_Share_REG GENERIC_File_Share_UNREG GENERIC_Mark_Share_WRITE GENERIC_File_Share_CHECK socketpair.c GENERIC_socketpair stat_jacket.c GENERIC_stat_Jacket __UTC_GENERIC_STAT_JACKET statfs.c GENERIC_statfs symlink.c GENERIC_SYMLINK syslog.c GENERIC_closelog GENERIC_syslog tempnam_jacket.c GENERIC_tempnam_Jacket test_jackets.c main time_r.c GENERIC_localtime_r GENERIC_gmtime_r __UTCTZ_GENERIC_LOCALTIME_R __UTCTZ_GENERIC_GMTIME_R unexpected.c unexpected unix2vms.c GENERIC_external_name GENERIC_external_dir_name GENERIC_is_valid_VMS_file_spec unlink_jacket.c GENERIC_unlink_Jacket utils.c Various utility/support routines utime.c GENERIC_utime write.c GENERIC_WRITE writev.c GENERIC_writev x_support.c GENERIC_CONNECTION_NUMBER Other Files --------------------------------------- File Description --------------------------------------- gnu_public_license.txt GNU public license text file. makefile.vms Used to build the Porting Library. make_options.com Used by makefile.vms to create a linker options file. make_options.dat List of all Porting Library routine names. Used by make_options.com. make_opt_file.com Used by makefile.vms. make_3_76_1_vms_alpha.exe Pre-built make image for OpenVMS Alpha V7.1 or later. make_3_76_1_vms_vax.exe Pre-built make image for OpenVMS VAX V7.1 or later. -- end of file --