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.
This was a part of library.c but has been split off so it can be used with other c programs in the suite.
There are several platform dependencies in the code which we need to get right:
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.
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) |
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.
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 |
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)
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 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
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 characters 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 |
Returns the length (units size_t) of a character string s[len] with the trailing blanks removed.
Interface to CCPERR which avoids mixing FORTRAN and C code.
prints a non-fatal message using the Fortran i/o.
reports a fatal error with a given file. Calls fatal.
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.
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 version 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.
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).
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
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
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.
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.
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.
void *ccp4malloc(size_t size) |
This is a wrapper for the malloc function, which adds some error trapping
void *ccp4realloc(void *ptr, size_t size) |
This is a wrapper for the realloc function, which adds some error trapping
void *ccp4calloc(size_t nelem , size_t elsize) |
This is a wrapper for the calloc function, which adds some error trapping
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.
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 architecture for all input MTZ and map files for which qrarch is called.
N.B.: leaves the stream positioned just after the machine stamp.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
When an erroneous 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.
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!
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.
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.
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.
Routines often found in libU77.a or somesuch are missing on some systems, eg HPUX, AIX, and F2C and G77.
AIX | void idate (int iarray) |
F2C || G77 | int idate_ (int *iarray) |
Returns date in dd/mm/yy format from localtime().
HPUX || AIX | int ierrno () |
F2C || G77 | int ierrno_ () |
HPUX || AIX | void itime (int array) |
F2C || G77 | int itime_ (int *array) |
HPUX || AIX | float etime (float tarray) |
F2C || G77 | doublereal etime_ (float *tarray) |
F2C || G77 | int exit_ (int *status) |
F2C || G77 | int time_ () |
F2C || G77 | int getpid_ () |
F2C || G77 | int isatty_ (int *lunit) |
CALL_LIKE_MVS | int __stdcall ISATTY (int *lunit) |
F2C || G77 | int gerror_ (char *str, int Lstr) |
F2C || G77 | int ibset_ (int *a, int *b) |
F2C || G77 | int ibclr_ (int *a, int *b) |
F2C || G77 | int btest_ (int *a, int *b) |