Previous: VMS Fortran Extensions Up: Porting Fortran Next: Machine Dependencies
VMS-Specific Code
Many current VICAR applications and subroutines have VMS-specific code
embedded in them. Some of it is obvious, like a system service call.
Some is insidiously difficult to find, like using a double precision floating
point value as a single. This works on the VAX because the first half of a
double value looks like a float. This is not the case on any other machine.
All the VMS-specific code must, of course, be eliminated or isolated. If the
same thing can be done in a portable way, do it that way. If not, then
isolate the VMS-specific code and write Unix code to perform the same
function. If the function is useful as a general-purpose subroutine, then
put it in SUBLIB. If not, include it with your code. See the next section
on Machine Dependencies for methods of dealing with machine-dependent code.
An attempt is made below to list the types of VMS-specific code you will run
into. This is not and can not be an exhaustive list, as there are far too
many potential problem areas that will only be uncovered with more experience.
Use this list as examples of what to look out for. You should be familiar
with writing portable Fortran code; if not then see a standard Fortran manual
(the black type in the VAX Fortran Language Reference Manual is a good
source). If in doubt, try it, or ask.
- The order of bytes in an integer (or any other data type) is
reversed on the VAX with respect to most other machines. Any code that
depends on byte order must be changed to not do so. Byte-order dependencies
typically come from converting between BYTE and other data types, where the
first byte of an integer is set to the value of a byte, then used as an
integer. This is typically accomplished via EQUIVALENCE. Use the
xvtrans routines or the BYTE2INT and INT2BYTE method
described above instead.
- INTEGERs and DOUBLE PRECISION floating point values must not be used
as INTEGER*2s or REALs without conversion. On the VAX, the address of a
double could be treated as the address of a real, or they could be equivalenced
to each other. This worked because the bit pattern for the first half of a
double is the same as for a real. The same is true for short vs. normal
integers - a pointer to an INTEGER could be treated as a pointer to an
INTEGER*2 or even a BYTE. This is not valid on any other machine. The
IEEE floating point standard (which most other machines use) uses different
bit patterns for doubles and for single-precision reals. For integers,
most other machines use the ``big-endian'' byte order. The first bytes
of an INTEGER are actually the higher-order bytes, unlike the VAX,
so the value cannot be treated as an INTEGER*2.
This practice is most common (and hardest to find!) in subroutine calls,
where a program is sloppy about passing data of the correct type. If the
subroutine expects a REAL, the value passed in better be a REAL and not a DOUBLE
PRECISION! The same is true for INTEGER, INTEGER*2, and BYTE. Be very
careful to watch out for this, as it is difficult to find.
- VMS System Calls must be eliminated or isolated. These include a whole
range of things, like system services (SYS$), VMS Run-Time Library calls
(LIB$, etc., not to be confused with the VICAR RTL), RMS calls or structures,
QIO calls for I/O, AST's (asynchronous system traps), and anything else that
is VMS specific. Any subroutine or structure with a dollar sign ($) in it
is suspect, as most VMS system routines have a $ in the name.
There are basically two choices for dealing with these. The first is to
dispense with system-specific calls and do things in a standard way, when
possible. This could be achieved by using standard Unix-style calls that
do the same thing (many of which are implemented under VMS), which may imply
calling C code that calls the Unix routines. The second is to isolate the
VMS-specific code, and write corresponding code that works on a Unix system.
Both versions could either be included as separate modules in the program
itself, or they could be put in a SUBLIB subroutine if it's a capability that
could be generally useful. See the next section for ways of handling
machine-dependent code. In general, system routines should not be called
from Fortran, as there is little standardization.
- Assembly language (called Macro on the VAX) included in the program
will of course have to be rewritten. You could write assembler versions for
every machine supported, but this is highly discouraged. The best
solution is to write the subroutine in a high-level language, preferably C.
Fortran could be used, but C is generally a better match to assembly language.
Section , Porting C, has more details about handling VAX MACRO.
- Character strings must be CHARACTER*n variables instead of BYTE,
LOGICAL*1, or INTEGER arrays. This topic is discussed in depth above.
- Fortran-C interfaces will have to be checked. There are several rules
for mixing Fortran and C, including having separate names for subroutines that
are to be called from both Fortran and C. Make sure you don't call a
subroutine from Fortran by its C interface, or vice-versa, as that is not
portable. String handling is a particular problem. See
Section , Mixing Fortran and C, for details.
- Make sure that all input operations from files can accept files
written on a foreign machine. This is often handled automatically, but there
are cases where it is not. See Section , Data Types and Host
Representations, for details.
- Do not assume that you know the size of a pixel in an input file.
An integer may not be four bytes on every machine that VICAR runs on.
Use the RTL routines xvpixsize, xvpixsizeu, or xvpixsizeb
to get the size of a pixel.
- Knowledge of the bit patterns used to store data is not portable,
especially floating-point data. This is not very common, but any code
that does bit-twiddling is likely to have problems. Byte-order dependencies
often creep into this sort of code.
- Use of EQUIVALENCE to access the same bit pattern in different ways is
highly unportable. If EQUIVALENCEs are used, make sure you use only one of the
definitions for any given piece of data. If you use the other definition, you
must put a new value of that type into the EQUIVALENCE. Be careful when mixing
INTEGER and REAL data types in a single array (the Fortran way of doing
structures). While that can be legitimate if done properly, care has to be
taken since the data sizes may not be the same on all machines.
- Optional arguments are not allowed in subroutines. You must supply
all the arguments the subroutine requires. If you are porting a subroutine
that accepts optional arguments, you have the choice of eliminating the
extra arguments, forcing them to be there, or creating different subroutine
names with different numbers of arguments.
- Do not use numeric constants for things like error numbers. VICAR
constants could change in the future, and ``CANNOT_FIND_KEY'' is much more
understandable than ``-38''. Use the VICAR include files when needed.
- Make sure that variable and subroutine names do not conflict with Unix
system routines or the RTL internal routines. Most Unix machines do not have
the concept of a shareable image like VMS does. Shareable images allowed
subroutine libraries such as the RTL to hide their internals from the program.
Without them, the entire RTL is linked with your program. This greatly
increases the chance of name collisions, as the internal RTL subroutine
names (and TAE and SPICE and X-windows and ...) are suddenly visible, and
some of the names are fairly common. Be very careful with subroutine and
global variable names.
The ultimate solution to this problem is to have a consistent naming scheme
for RTL internal names that won't conflict with applications. Until this
is implemented, however, you must watch out for conflicts. Even this fix won't
help other subroutine packages that MIPL does not have direct control over,
such as TAE, SPICE, and X-windows.
- There are many differences in the file system and filename structure
between VMS and Unix. The VMS pathname of
``disk:[dir.subdir]file.ext;version'' is quite different from the
Unix pathname of ``/dir/subdir/subdir/filename''. Logical names do
not exist under Unix. The analog to logical names, environment variables,
act quite differently in many respects (for example, the system open()
call doesn't know how to deal with environment variables, although xvopen
does). Filenames and pathnames that are embedded in the program should be
removed and made available as arguments, both to handle architecture
differences and differences in directory structure on other machines. Any
code that parses filenames from user input must be aware of the differences
and have code to handle each system. Such code should be rare as the RTL does
most of the filename parsing; however, it does exist.
- Filenames and pathnames tend to be longer under Unix than VMS. Many
current programs arbitrarily limit filename parameters to 40 or even 20
characters in the PDF and in the code. These limits need to be lifted.
Most of the time, the program never sees the filename (it lets xvunit
take care of it), so the solution is simply to not specify the maximum string
length in the PDF. Instead of saying ``(STRING,40)'', just say ``STRING''.
If you need a buffer in the program code to handle the filename, allow at
least 255 characters (which is slightly more than the maximum TAE string size).
- The filenames of the program units themselves will need changing.
Fortran language modules must end in a ``.f'', not ``.for'', to be
compatible with vimake. That is because Unix likes ``.f'', and it is
more picky about filename extensions than VMS is. Other files have naming
rules as well. See Section , vimake, for details.
- Many VAX Fortran language extensions are present in current VICAR code.
A small subset of extensions is allowed (they are listed above), since they
are available on all machines of interest. All other extensions will
have to be removed, as they are not portable. Check the VAX Fortran
Language Reference Manual for the feature in question. If it is printed in
blue ink, then it is not portable and may not be used, unless it is in the
above list.