
|
LIBRARY (CCP4: Library)
NAME
library - the CCP4 C subroutine library
DESCRIPTION
library.c is a set of low-level C routines used by
ccplib and
diskio. There is also a header file
library.h which should be included in any C program which
uses CCP4 routines, as this contains code for dealing with platform
dependencies.
CONTENTS
Notes on the header file library.h
This was a part of library.c but has been split off so it can be used
with other c programs in the suite.
Comments on platform dependencies
There are several platform dependencies in the code which we need to
get right:
- Fortran/C conventions The calling conventions for C from
Fortran vary from compiler to compiler;
- Header files etc. We can't assume everything has ANSI C
or POSIX libraries;
- Real number format for the transparent binary i/o;
- Special things The putenv/setenv call isn't defined in
the current standards.
Assumptions
It is assumed that a Fortran INTEGER corresponds to a C
int, and that a Fortran REAL corresponds to a C
float.
Also, the identity of certain calling conventions is only
guaranteed if the routines have only a single Fortran
CHARACTER-type argument - since in some cases the length of each
such argument is given after it in the parameter list, and in other cases
they are all collected at the end of the list.
Apart from the possibility of using the Netlib f2c
compiler we currently assume that each system uses the vendor-supplied
Fortran compiler.
This is for IBM Unix systems - RS/6000 models, at least.
The compiler can append "_" (underscore character) to external names, but we
assume the default where this doesn't happen. See configure for the
enforcement of this.
Platform Identification
The guarded code in library.h is executed when we've identified
the platform, so each type of system we know about should cause KNOWN_MACHINE
to be defined; it will also define CALL_LIKE_something, depending
on the calling conventions used by that system. For example:
#if defined (sgi)
# define KNOWN_MACHINE
# define CALL_LIKE_SUN 1
#endif
Thus if you know system foo has the same Fortran calling
convention as that used by the native Sun compiler, then define
CALL_LIKE_SUN and you won't need to examine the definitions of the
interface functions below. Note that further tests on the system type may be
necessary, for example to get the include files right.
The calling conventions for the major platforms supported by CCP4
are given below:
CALL_LIKE_ | Systems
|
---|
HPUX | AIX, HPUX
| SUN | Alliant, Convex, ESV, SGI, Sun, Ultrix, OSF1, Linux, LinuxPPC
| STARDENT | Ardent/Titan/Stardent
| VMS | VMS
| MVS | Microsoft Visual Studio (NT)
|
Practical implementation for different platforms
Once the KNOWN_MACHINE and CALL_LIKE_something variables have
been defined, the correct calling conventions are invoked in library.c
by the presence of code of the form
...
#if CALL_LIKE_HPUX
void copen (int *iunit, char *filename, int *istat, int Lfilename);
#endif
#if CALL_LIKE_STARDENT
void COPEN (int *iunit, struct Str_Desc *filename, int *istat);
#endif
#if defined (VMS)
void COPEN (int *iunit, struct dsc$descriptor_s *filename, int *istat);
#endif
#if CALL_LIKE_SUN
void copen_ (int *iunit, char *filename, int *istat, int Lfilename);
#endif
...
Examine the source code for more exact details of how this works in practice.
File mode definitions
Here are the definitions of the diskio modes, specifying the
type of data transfer: bytes, half-words, integers, reals,
half(integer)-word complex and complex, respectively:
define | BYTE | 0
| define | INT16 | 1
| define | INT32 | 6
| define | FLOAT32 | 2
| define | COMP32 | 3
| define | COMP64 | 4
|
Converting foreign binary number formats
The library is intended to allow the binary file formats MTZ
and map files to be read satisfactorily if they were
written on another platform. Such files are always written in the
native real or integer number format with a machine
stamp in the file to identify the formats involved. Then, if
necessary, conversion is done from the foreign format to native when
the file is read. There is thus only a significant overhead for files
imported from platforms with different number formats; locally-written files
are read back optimally and there is no write overhead.
When converting from foreign to native formats we're potentially faced
with a combinatorial explosion---currently combinations of ieee
little-endian, ieee big-endian, VAX and Convex native
formats. (This applies only to real number formats---fortunately
everything we're interested in has twos complement integers.) Thus we
first make sure that the format is converted to canonical form (which
we choose as big-endian ieee) and then, if
necessary, to the native format in a separate stage.
The basic idea of this is due to David Wild (EMBL, Hamburg, 1991).
His original, partially-functional implementation used code from the
HDF 3.1 distribution. This re-write is by Dave Love, very
loosely based on HDF3.3, but doing the conversion in-place. It works
for the full set of relevant systems and no longer has MTZ- and
map-specific code in copen. (HDF stuff can be found on
ftp.ncsa.uiuc.edu)
Machine stamps
The machine stamp is a 32-bit quantity containing a set of four
`nibbles' (half-bytes)---only half the space is used. Each nibble is
a number specifying the representation of (in C terms) double (d)
, float (f), int (i) and unsigned char (c)
types. Thus each stamp is of the form 0xdfic0000. The
values for the floating point nibbles may be taken from the list (following HDF):
1 | Big-endian ieee
| 2 | VAX
| 3 | Cray
| 4 | Little-endian ieee
| 5 | Convex native
| 6 | Fijitsu VP
|
The Cray isn't relevant to us because it's not a 32-bit machine
and we don't currently have a use for the Fujitsu one, which isn't
implemented here. We ignore the possibility of
non-ascii characters which might need
converting e.g., from ebcdic, so c is
always 1; also f and d are the same (as per Fortran). See the
HDF code for character code possibilities.
Here are the tags for different formats as used in the code.
class info codes for int
| DFNTI_MBO | 1 | Motorola byte order 2's compl
| DFNTI_IBO | 4 | Intel byte order 2's compl
| class info codes for float
| DFNTF_BEIEEE | 1 | big endian IEEE (canonical)
| FNTF_VAX | 2 | Vax format
| DFNTF_CONVEXNATIVE | 5 | Convex native floats
| DFNTF_LEIEEE | 4 | little-endian IEEE format
|
Following are definitions. Note that some of the symbols
tested here to determine the machine type might need to be qualified
in the future where they don't necessarily determine the architecture.
Only nativeFT and nativeIT, which determine the
native real and integer formats, are set.
#if defined (VAX) || defined (vax) /* gcc seems to use vax */
# define NATIVEFT DFNTF_VAX
# define NATIVEIT DFNTI_IBO
#endif
Here are the possibilities for little-endian ieee. (The
MIPS compilers define MIPSEL or MIPSEB depending on the
mode in which the the chip operates.) The architectures covered here
include some DECstations, i860 and
Intel chips like PCs and Alpha (sometimes!).
#if defined(MIPSEL) || defined(alliant) || defined(i386) || defined(i860)
# define NATIVEIT DFNTI_IBO
# define NATIVEFT DFNTF_LEIEEE
#endif
Machines using the powerPC chip.
Specifically, this has been tried on PowerMacs running LinuxPPC, which
appears to be big-endian. But in principle the powerPC chip can support
both big-endian and little-endian OS's under software control. The
symbol "powerpc" appears in gcc-2.8.1/config/rs6000/linux.h and appears
to distinguish LinuxPPC from other OS's for this chip.
#if defined (powerpc)
# define NATIVEIT DFNTI_MBO
# define NATIVEFT DFNTF_BEIEEE
#endif
Alpha VMS is a pain: compiler switches can force
VAX or ieee number formats. Thus if we know it's an Alpha,
we have to check for VMS and then what sort of VMS numbers. [OSF and
OpenVMS define __alpha, OpenVMS, only __ALPHA.
#ifdef __alpha
# ifdef VMS
# if __IEEE_FLOAT == 1
# define NATIVEFT DFNTF_LEIEEE
# else
# define NATIVEFT DFNTF_VAX
# endif
# else /* assume OSF/1 */
# define NATIVEFT DFNTF_LEIEEE
# endif
# define NATIVEIT DFNTI_IBO
#endif
Big-endian ieee includes SGI machines,
HP machines (68k-based or RISC), RS/6000 and all
Suns except the obsolete i386-based ones.
(Apollo}s are also apparently in this category.)
#if defined(MIPSEB) || defined(__hpux) || defined(_AIX) || defined(m68k) ||
defined(mc68000) || defined(sparc) || defined (__sparc__)
# define NATIVEIT DFNTI_MBO
# define NATIVEFT DFNTF_BEIEEE
#endif
Convex}s can operate in either native or ieee mode:
#if defined(__convex__) || defined(__convexc__)
# define NATIVEIT DFNTI_MBO
# ifdef _IEEE_FLOAT_
# define NATIVEFT DFNTF_BEIEEE
# else
# ifdef _CONVEX_FLOAT_
# define NATIVEFT DFNTF_CONVEXNATIVE
# else
#error "Can't determine Convex floating point type. Use native compiler"
# endif
# endif
#endif
#ifndef NATIVEFT
#error "Can't determine machine number format"
#endif
Notes on routines in library.c
This file contains the lowest level routines for the CCP4 Program
Suite, mainly for i/o (as required by the diskio routines) and
bit-twiddling.
The following routines are defined:
Routine | Purpose
|
---|
Internal routines
| flength
| return length of string less trailing blanks
| fatal
| interface to ccperr
| cqprint
| prints a message to FORTAN i/o
| file_fatal
| reports fatal error
| FP conversion routines
| vaxF2ieeeF | VAX(double) <-> ieee(float)
| ieeeF2vaxF | ieee(double) <-> VAX(float)
| convexF2ieeeF | Convex(double) <-> ieee(float)
| ieeeF2convexF | ieee(double) <-> Convex(float)
| Miscellaneous routines
| ustenv
| set an environment variable
| cunlink
| unlinks file from directory
| hgetlimits
| get int and float limits
| cmkdir
| wrap around for mkdir function
| cchmod
| wrap around for chmod function
| Dynamic memory allocation
| ccpal1
| calls routine with array arguments
| ccp4malloc
| wrap around for malloc function
| ccp4realloc
| wrap around for realloc function
| ccp4calloc
| wrap around for calloc
| Disk i/o routines
| copen
| open random access file using fopen
| qrarch
| set up diskio number translation
| qwarch
| write `machine stamp' to diskio file
| qclose
| shut random access file using fclose
| qmode
| change size of item in file ops.
| qread
| fread from random access file
| qreadc
| fread byte characters from random access file
| qwrite
| fwrite to random access file
| qwritc
| fwrite byte charactes to random access file
| qseek
| fseek within random access file
| qback
| backspace within random access file
| qskip
| skip forward within random access file
| cqinq
| inquire file status on the given stream
| qlocate
| current position within random access file
| Magic numbers
| qnan
| sets NaN
| cisnan
| checks for NaN
| ccpbml
| absent data test for mtzlib
| ccpwrg
| updates MTZ column ranges
| Missing system support
| idate/idate_ | AIX, F2C, G77
| ierrno/ierrno_ | HPUX, AIX, F2C, G77
| itime/itime_ | HPUX, AIX, F2C, G77
| etime/etime_ | HPUX, AIX, F2C, G77
| exit_ | F2C, G77
| time_ | F2C, G77
| getpid_ | F2C, G77
| isatty/isatty_ | HPUX, AIX, F2C, G77
| gerror_ | F2C, G77
| ibset_ | F2C, G77
| ibclr_ | F2C, G77
| btest_ | F2C, G77
|
Routine Descriptions
Internal Routines.
flength
- static size_t flength (char *s, int len)
Returns the length (units size_t) of a character string s[len] with the
trailing blanks removed.
fatal
- static void fatal (char *message)
Interface to CCPERR which avoids mixing FORTRAN and C code.
cqprint
- static void cqprint (char *message)
prints a non-fatal message using the Fortran i/o.
file_fatal
- static void file_fatal (char *message, char *file)
reports a fatal error with a given file. Calls fatal.
Floating-point conversion routines.
These conversion routines are based on HDF, but do the
conversion in-place. They do the obvious conversion between VAX,
IEEE and Convex formats implied by the routine names.
vaxF2ieeeF
- static void vaxF2ieeeF(union float_uint_uchar buffer[], int size)
ieeeF2vaxF
- static void ieeeF2vaxF(union float_uint_uchar buffer[], int size)
The Convex format is like the VAX with a different byte order.
Convex does provide ieee native ieee conversion routines,
but we need convexF2ieeeF anyhow.
convexF2ieeeF
- static void convexF2ieeeF(union float_uint_uchar buffer[], int size)
ieeeF2convexF
- static void ieeeF2convexF(union float_uint_uchar buffer[], int size)
Miscellaneous routines.
ustenv
CALL_LIKE_HPUX:
| void ustenv (char *string, int *result, int Lstr)
| CALL_LIKE_STARDENT:
| void USTENV (struct Str_Desc *string, int *result)
| CALL_LIKE_SUN:
| void ustenv_ (char *string, int *result, int Lstr)
| CALL_LIKE_MVS:
| void __stdcall USTENV (char *string, int *result, int Lstr)
|
This sets an environment variable var to val, where the
argument string == 'var=val'. This is for use by the "logical name"
mechanism for specifying file connexions. Note that a VMS varsion is supplied
in vms.for and that there is no standard way of setting and environment
variable. In a minimal posix system it might be necessary to twiddle the
environment strings explicitly.
cunlink
CALL_LIKE_HPUX
| void cunlink (char *filename, int Lfilename)
| CALL_LIKE_STARDENT
| void CUNLINK (struct Str_Desc *filename)
| (VMS)
| void CUNLINK (struct dsc$descriptor_s *filename)
| CALL_LIKE_SUN
void cunlink_ (char *filename, int Lfilename)
| CALL_LIKE_MVS
| void __stdcall CUNLINK (char *filename, int Lfilename)
| |
This unlinks filename from the directory. It's intended for
use with scratch files, so that they can be hidden when opened but still
be available as long as they remain connected (see CCPOPN).
This functionality doesn't seem to exist in VMS. Failure to
unlink isn't fatal (it's been observed, apparently spuriously).
hgetlimits
CALL_LIKE_HPUX
| void hgetlimits (int *IValueNotDet, float *ValueNotDet)
| (VMS)
| void HGETLIMITS (int *IValueNotDet, float *ValueNotDet)
| CALL_LIKE_STARDENT
| void HGETLIMITS (int *IValueNotDet, float *ValueNotDet)
| CALL_LIKE_SUN
| void hgetlimits_ (int *IValueNotDet, float *ValueNotDet)
| CALL_LIKE_MVS
| void __stdcall HGETLIMITS (int *IValueNotDet, float *ValueNotDet)
|
Returns largest int and largest float as defined in limits.h
and float.h
cmkdir
CALL_LIKE_HPUX
| void cmkdir (const char *path, const char *cmode, int *result,
int Lpath, int Lmode)
| (VMS)
| void CMKDIR (struct dsc$descriptor_s *path,
struct dsc$descriptor_s *cmode, int *result)
| CALL_LIKE_STARDENT
| void CMKDIR (struct Str_Desc *path, struct Str_Desc *cmode,
int *result)
| CALL_LIKE_SUN
| void cmkdir_ (const char *path, const char *cmode, int *result,
int Lpath, int Lmode)
| CALL_LIKE_MVS
| void __stdcall CMKDIR (const char *path, int Lpath,
const char *cmode, int Lmode, int *result)
|
Wrap-around for mkdir function. Returns 0 if successful, 1 if directory
already exists, and -1 if other error
cchmod
CALL_LIKE_HPUX
| void cchmod (const char *path, const char *cmode, int *result,
int Lpath, int Lmode)
| (VMS)
| void CCHMOD (struct dsc$descriptor_s *path,
struct dsc$descriptor_s *cmode, int *result)
| CALL_LIKE_STARDENT
| void CCHMOD (struct Str_Desc *path, struct Str_Desc *cmode,
int *result)
| CALL_LIKE_SUN
| void cchmod_ (const char *path, const char *cmode, int *result,
int Lpath, int Lmode)
| CALL_LIKE_MVS
| void __stdcall CCHMOD (const char *path, int Lpath,
const char *cmode, int Lmode, int *result)
|
Wrap around for chmod function.
Dynamic memory allocation
It's nice to be able to determine array sizes at run time to avoid
messy recompilation. The only way effectively to get dynamic
allocation in Fortran77 reasonably portably is to do the allocation,
e.g.\ in C, and invoke the Fortran routine passed as a parameter with
pointers to the allocated memory which it will treat as arrays. If we
want to allow more than one array, it's more tricky.
ccpal1
CALL_LIKE_HPUX
| void ccpal1 (void (* routne), int *n, int type[], int length[])
| (VMS) || CALL_LIKE_STARDENT
| void CCPAL1 (void (* routne) (), int *n, int type[], int length[])
| CALL_LIKE_SUN
| void ccpal1_ (void (* routne) (), int *n, int type[], int length[])
| CALL_LIKE_MVS
| void __stdcall CCPAL1 (void (* routne) (), int *n, int type[], int length[])
|
Arranges to call subroutine routne with n array
arguments. Each has a type indicated by type(i) and a length
given by length(i). type is an integer array with
values 1, 2, 3, 4 indicating INTEGER, REAL, DOUBLE PRECISION and COMPLEX
respectively. It's not immediately clear what all the Fortran/C
conventions are for passing CHARACTER arrays, so we'll arrange a
higher-level interface and have types here just numeric. The
Fortran (CCPALC) will also do argument validation. Also the rules
for passing external routines as arguments aren't clear--assume
the obvious way.
There's a VMS Fortran version of this, although the code here
does work fine in VMS\@.
NB: there's a possibility of a hook here to use memory-mapped files on
systems with the capability and insufficient VM.
Under protest, this now allocates zeroed storage for where programs
make bad assumptions.
ccp4malloc
void *ccp4malloc(size_t size)
|
This is a wrapper for the malloc function, which adds some
error trapping
ccp4realloc
void *ccp4realloc(void *ptr, size_t size)
|
This is a wrapper for the realloc function, which adds some
error trapping
ccp4calloc
void *ccp4calloc(size_t nelem , size_t elsize)
|
This is a wrapper for the calloc function, which adds some
error trapping
Diskio Routines.
copen
CALL_LIKE_HPUX
| void copen (int *iunit, char *filename, int *istat, int Lfilename)
| CALL_LIKE_STARDENT
| void COPEN (int *iunit, struct Str_Desc *filename, int *istat)
| (VMS)
| void COPEN (int *iunit, struct dsc$descriptor_s *filename, int *istat)
| CALL_LIKE_SUN
| void copen_ (int *iunit, char *filename, int *istat, int Lfilename)
| CALL_LIKE_MVS
| void __stdcall COPEN (int *iunit, char *filename, int Lfilename, int *istat)
|
Opens filename on diskio stream iunit. istat
corresponds to the open mode given to qopen, from which copen
is always called--see diskio documentation.
qrarch
CALL_LIKE_HPUX
| void qrarch (int *iunit, int *ipos, int *ireslt)
| CALL_LIKE_STARDENT || (VMS)
void QRARCH (int *iunit, int *ipos, int *ireslt)
| CALL_LIKE_SUN
void qrarch_ (int *iunit, int *ipos, int *ireslt)
| CALL_LIKE_MVS
void __stdcall QRARCH (int *iunit, int *ipos, int *ireslt)
| | | |
For binary files with a well-determined structure in terms of
float's and int's we may want to set up the connected stream to
do transparent reading of files written on a machine with a different
architecture. This is currently the case for map files and
MTZ files and this routine is called from mtzlib and
maplib.
qrarch reads the "machine stamp" at word ipos
for the diskio file on stream iunit and sets up the appropriate
bit-twiddling for subsequent qreadi's on that stream. The
information read from the file is returned in ireslt in the
form fileFT+16*fileIT. If the stamp is zero
(as it would be for files written with a previous version of the
library) we assume the file is in native format and needs no
conversion in qread; in this case ireslt
will be zero and
the caller can issue a warning. Iconvert and Fconvert are
used by qread to determine the type of conversion (if any) to be
applied to integers and reals.
Extra feature: logical/environment variable CONVERT_FROM may be set
to one of BEIEEE, LEIEEE, VAX or
CONVEXNATIVE to avoid reading the
machine stamp and assume the file is from the stipulated archictecture
for all input MTZ and map files for which qrarch is called.
N.B.: leaves the stream positioned just after the machine stamp.
qwarch
CALL_LIKE_HPUX
| void qwarch (int *iunit, int *ipos)
| CALL_LIKE_STARDENT || (VMS)
| void QWARCH (int *iunit, int *ipos)
| CALL_LIKE_SUN
| void qwarch_ (int *iunit, int *ipos)
| CALL_LIKE_MVS
| void __stdcall QWARCH (int *iunit, int *ipos)
|
This is the complement of qrarch, writing the native
machine architecture information ("machine stamp") to diskio stream
iunit at word ipos. Currently called
from mtzlib and maplib.
The machine stamp in mtstring is four nibbles in order, indicating
complex and real format (must both be the same), integer format and
character format (currently irrelevant). The last two bytes of
mtstring are currently unused and always zero.
N.B.: leaves the stream positioned just after the machine stamp.
qclose
CALL_LIKE_HPUX
| void qclose (int *iunit)
| (VMS) || CALL_LIKE_STARDENT
| void QCLOSE (int *iunit)
| CALL_LIKE_SUN
| void qclose_ (int *iunit)
| CALL_LIKE_MVS
| void __stdcall QCLOSE (int *iunit)
|
Closes the file open on diskio stream iunit.
qmode
CALL_LIKE_HPUX
| void qmode (int *iunit, int *mode, int *size)
| (VMS) || CALL_LIKE_STARDENT
| void QMODE (int *iunit, int *mode, int *size)
| CALL_LIKE_SUN
| void qmode_ (int *iunit, int *mode, int *size)
| CALL_LIKE_MVS
| void __stdcall QMODE (int *iunit, int *mode, int *size)
|
Changes the diskio "access mode" for stream iunit to
mode. The resulting size in bytes of items for transfer is
returned as size.
qread
CALL_LIKE_HPUX
| void qread (int *iunit, uint8 * buffer, int *nitems, int *result)
| (VMS) || (stardent)
| void QREAD (int *iunit, uint8 * buffer, int *nitems, int *result)
| CALL_LIKE_SUN
| void qread_ (int *iunit, uint8 * buffer, int *nitems, int *result)
| CALL_LIKE_MVS
| void __stdcall QREAD (int *iunit, uint8 * buffer, int *nitems, int *result)
|
Reads nitems in the current mode (set by qmode
) from diskio stream iunit previously opened by
qqopen
(copen) and returns result which is
0 on success, or -1 at EOF.
It aborts on an i/o error.
Numbers written in a foreign format will be translated if necessary if
the stream is connected to an MTZ or map file.
qreadc
CALL_LIKE_HPUX
| void qreadc (int *iunit, char * buffer, int *result, int Lbuffer)
| VMS
| void QREADC (int *iunit, struct dsc$descriptor_s *buffer, int *result)
| CALL_LIKE_STARDENT
| void QREADC (int *iunit, struct Str_Desc *buffer, int *result)
| CALL_LIKE_SUN
| void qreadc_ (int *iunit, char * buffer, int *result, int Lbuffer)
| CALL_LIKE_MVS
| void __stdcall QREADC (int *iunit, char * buffer, int *result, int Lbuffer)
|
Fills CHARACTER buffer in byte mode from diskio stream
iunit previously opened by qqopen
(copen) and returns
result which is the number of items read or 0 on failure.
Call it with a character substring if necessary to control the number
of bytes read.
qwrite
CALL_LIKE_HP
| void qwrite (int *iunit, uint8 * buffer, int *nitems)
| (VMS) || CALL_LIKE_STARDENT
| void QWRITE (int *iunit, uint8 * buffer, int *nitems)
| CALL_LIKE_SUN
| void qwrite_ (int *iunit, uint8 * buffer, int *nitems)
| CALL_LIKE_MVS
| void __stdcall QWRITE (int *iunit, uint8 * buffer, int *nitems)
|
This writes nitems items from buffer to
opened stream iunit using the current mode.
qwritc
CALL_LIKE_HPUX
| void qwritc (int *iunit, char * buffer, int Lbuffer)
| (VMS)
| void QWRITC (int *iunit, struct dsc$descriptor_s *buffer)
| CALL_LIKE_STARDENT
| void QWRITC (int *iunit, struct Str_Desc *buffer)
| CALL_LIKE_SUN
| void qwritc_ (int *iunit, char * buffer, int Lbuffer)
| CALL_LIKE_MVS
| void __stdcall QWRITC (int *iunit, char * buffer, int Lbuffer)
|
Writes CHARACTER*(*) buffer to opened stream iunit in
byte mode.
qseek
CALL_LIKE_HPUX
| void qseek (int *iunit, int *irec, int *iel, int *lrecl)
| (VMS) || CALL_LIKE_STARDENT
| void QSEEK (int *iunit, int *irec, int *iel, int *lrecl)
| CALL_LIKE_SUN
| void qseek_ (int *iunit, int *irec, int *iel, int *lrecl)
| CALL_LIKE_MVS
| void __stdcall QSEEK (int *iunit, int *irec, int *iel, int *lrecl)
|
Seeks to element iel in record irec in diskio stream
iunit whose record length is lrecl.
qback
CALL_LIKE_HPUX
| void qback (int *iunit, int *lrecl)
| (VMS) || CALL_LIKE_STARDENT
| void QBACK (int *iunit, int *lrecl)
| CALL_LIKE_SUN
| void qback_ (int *iunit, int *lrecl)
| CALL_LIKE_MVS
| void __stdcall QBACK (int *iunit, int *lrecl)
|
Backspaces one record, of length lrecl on diskio stream
iunit.
cqinq
CALL_LIKE_HPUX
| void cqinq (int *istrm, char *filnam, int *length, int len_filnam)
| CALL_LIKE_STARDENT
| void CQINQ (int *istrm, struct Str_Desc *filnam, int *length)
| (VMS)
| void CQINQ (int *istrm, struct dsc$descriptor_s *filnam, int *length)
| CALL_LIKE_SUN
| void cqinq_ (int *istrm, char *filnam, int *length, int len_filnam)
| CALL_LIKE_MVS
| void __stdcall CQINQ (int *istrm, char *filnam, int len_filnam, int *length)
|
Returns the name filnam and length of the file (if any)
open on diskio stream istrm.
qlocate
CALL_LIKE_HPUX
| void qlocate (int *iunit, int *locate)
| (VMS) || CALL_LIKE_STARDENT
| void QLOCATE (int *iunit, int *locate)
| CALL_LIKE_SUN
| void qlocate_ (int *iunit, int *locate)
| CALL_LIKE_MVS
| void __stdcall QLOCATE (int *iunit, int *locate)
|
Returns the current position locate in the diskio stream
iunit.
`Magic' numbers
When an erronous result occurs, for instance a floating point exception,
it is useful to give it a special value--a "magic number"--possibly in
addition to a special value, like a negative one.
Using such a number in a calculation (by mistake, through ignoring the
value) should not allow one to get half-sensible
results as one might if this number was -9999 or some such.
The obvious tactic with ieee arithmetic is to use a NaN
value in such situations. Things may be set up so that we either get
an exception on using it in arithmetic or it silently propagates to all
values using it and its presence is indicated by a NaN in the output.
We need to provide a means of setting the magic number and checking
whether a given value is such. These are architecture-dependent
bit-level operations, hence their presence in the C code.
The suite doesn't currently use these routines, but should do soon.
qnan
CALL_LIKE_HPUX
| void qnan (union float_uint_uchar *realnum)
| (VMS) || CALL_LIKE_STARDENT
| void QNAN (union float_uint_uchar *realnum)
| CALL_LIKE_SUN
| void qnan_ (union float_uint_uchar *realnum)
| CALL_LIKE_MVS
| void __stdcall QNAN (union float_uint_uchar *realnum)
|
Sets a value to NaN.
We have a choice of NaN values in ieee arithmetic.
0xfffa5a5a is the one used by the MIPS compilers as an
undefined value. Note the hex constant is the same for both byte sexes!
cisnan
CALL_LIKE_HPUX
| int cisnan (union float_uint_uchar *realnum)
| (VMS) || CALL_LIKE_STARDENT
| int CISNAN (union float_uint_uchar *realnum)
| CALL_LIKE_SUN
| int cisnan_ (union float_uint_uchar *realnum)
| CALL_LIKE_MVS
| int __stdcall CISNAN (union float_uint_uchar *realnum)
|
integer (logical) function cisnan tests whether its argument
is a NaN. We have to do this by writing a C
int-valued procedure and testing the returned value in the calling
function so that we don't have to assume how it represents logical
values. The diskio library library provides the
trivial interface qisnan.
ccpbml
CALL_LIKE_HPUX
| void ccpbml (int *ncols, union float_uint_uchar cols[])
| (VMS) || CALL_LIKE_STARDENT
| void CCPBML (int *ncols, union float_uint_uchar cols[])
| CALL_LIKE_SUN
| void ccpbml_ (int *ncols, union float_uint_uchar cols[])
| CALL_LIKE_MVS
| void __stdcall CCPBML (int *ncols, union float_uint_uchar cols[])
|
Absent data test for mtzlib.
In mtzlib there's a fudge for BIOMOL-convention absence
flags, which are re-written to zeroes. To do the real number
comparison, though, it's necessary to do a qnan-type test first.
We don't want to call qnan (which calls cisnan) on every
number in the data file, so the tests are amortised in this routine
which deals with a whole array cols of length ncols.
ccpwrg
CALL_LIKE_HPUX
void ccpwrg (int *ncols, union float_uint_uchar cols[],
float wminmax[])
| (VMS) || CALL_LIKE_STARDENT
| void CCPWRG (int *ncols, union float_uint_uchar cols[],
float wminmax[])
| CALL_LIKE_SUN
| void ccpwrg_ (int *ncols, union float_uint_uchar cols[],
float wminmax[])
| CALL_LIKE_MVS
| void __stdcall CCPWRG (int *ncols, union float_uint_uchar cols[],
float wminmax[])
| |
For updating MTZ column ranges.
This is a similar fudge to ccpbml to avoid QISNAN calls in
updating the MTZ column ranges in mtzlib. Note that wminmax
actually indexes a 3-D Fortran array with the first
dimension range of 2, indicating minimum and maximum values respectively.
Missing system support
Routines often found in libU77.a or somesuch are missing
on some systems, eg HPUX, AIX, and F2C and G77.
idate
AIX
| void idate (int iarray)
| F2C || G77
| int idate_ (int *iarray)
|
Returns date in dd/mm/yy format from localtime().
ierrno
HPUX || AIX
| int ierrno ()
| F2C || G77
| int ierrno_ ()
|
itime
HPUX || AIX
| void itime (int array)
| F2C || G77
| int itime_ (int *array)
|
etime
HPUX || AIX
| float etime (float tarray)
| F2C || G77
| doublereal etime_ (float *tarray)
|
exit_
F2C || G77
| int exit_ (int *status)
|
time_
-
getpid_
F2C || G77
| int getpid_ ()
|
isatty
F2C || G77
| int isatty_ (int *lunit)
| CALL_LIKE_MVS
| int __stdcall ISATTY (int *lunit)
|
gerror_
F2C || G77
| int gerror_ (char *str, int Lstr)
|
ibset_
F2C || G77
| int ibset_ (int *a, int *b)
|
ibclr_
F2C || G77
| int ibclr_ (int *a, int *b)
|
btest_
F2C || G77
| int btest_ (int *a, int *b)
|
|