gethdr, getelcnt, getslice, gislice, gaslice, puthdr, putslice, pislice, paslice, nullhdr, copycmt, copypar, copyfld, addcline, addcommand, addpar, addfld, getcmt, getpar, seekpar, getfld, seekfld, getfmt, elemcnt, getilist, getbuff, getptr, getptr2, subspace1, floatswap: C language routines to read, write, and modify common data format files.
#include
<stdio.h>
#include cdfhdr.h
reading and writing common data format files:
gethdr(stream,buffer,max)
FILE *stream;
char buffer[][LINE];
int max;
This routine reads a common data format header into buffer from the file defined by stream. No more than max lines are read, to protect buffer from overflow. The file is assumed to be already open, and it is left positioned at the beginning of the static slice. The number of lines in the header is returned, and the routine dies if it can’t read the file.
long
getelcnt(stream)
FILE *stream;
This routine reads an element count from the file defined by stream and returns it. It returns −1 if an end of file is encountered. Stream is assumed to be open, and the file is left positioned after the element count. This routine is normally not used directly, as getslice reads both the element count and the slice data. This version handles both 8 character and 16 character element counts.
long
getslice(stream,num,sbuff)
FILE *stream;
long num;
float sbuff[];
This routine reads an element count and the corresponding slice of data (assumed to be in float format) from the file (assumed open) defined by stream. The file is positioned at the beginning of the next slice upon return. Getslice returns the number of elements read, or EOF if an end of file is encountered. Data is placed in the buffer pointed to by sbuff, which is normally dynamically allocated by the calling routine on the basis of the expected number of elements. If the expected number, num, doesn’t match the number actually found, getslice complains and dies. (Compute num using the routine elemcnt.) If num is negative or very very large, death also occurs.
long
gislice(stream,size,length,offset,add,mul,num,sbuff,swapflag)
FILE *stream;
int *size;
long *length,*offset;
float *add,*mul;
long num;
float sbuff[];
char swapflag;
This routine operates like getslice except that a slice in int format is expected. The arguments stream, num, and sbuff have the same meaning as in getslice, and data are converted to float format before being put into sbuff. The additional arguments (except for the last) are one dimensional arrays with one value for each field in the slice. The meanings are as follows: Size is the number of bytes taken up by elements of the field in question in int format. Length is the number of elements of the field, and offset is its position relative to the start of the slice. Add and mul give the additive and multiplicative constants used to convert between float and int formats. These additional fields are generally obtained from the header using the routine getilist. Pixel fields undergo no change in format. If the last argument, swapflag, is non-zero, byte ordering on shorts and longs is reversed. Pixel fields are not affected.
gaslice(stream,num,sbuff)
FILE *stream;
long num;
float sbuff[];
This routine works like getslice except that a slice buffer in ascii format is expected. The data are converted to float form before being put into sbuff. Pixel fields are assumed to be in hexidecimal format, one byte at a time.
puthdr(stream,buffer,max)
FILE *stream;
char buffer[][LINE];
int max;
This routine writes a common data format header contained in buffer into the file defined by stream, assumed open. A maximum of max lines will be written. Normal writes stop at the line containing a single asterisk, however.
long
putslice(stream,num,sbuff)
FILE *stream;
long num;
float *sbuff;
This routine writes an element count and a slice of data contained in sbuff to the file defined by stream. The number of elements to write is given by num. The file is assumed to be open, and the data is assumed to be in format float.
long
pislice(stream,size,length,offset,add,mul,num,sbuff)
FILE *stream;
int *size;
long *length,*offset;
float *add,*mul;
long num;
float sbuff[];
This routine operates like putslice except that a slice in int format is written. The arguments stream, num, and sbuff have the same meaning as in putslice, and data are expected in float format in sbuff. The additional arguments are one dimensional arrays with one value for each field in the slice. The meanings are as follows: Size is the number of bytes taken up by elements of the field in question in int format. Length is the number of elements of the field, and offset is its position relative to the start of the slice. Add and mul give the additive and multiplicative constants used to convert between float and int formats. These additional fields are generally obtained from the header using the routine getilist. Pixel fields are written with no change of format.
paslice(stream,num,sbuff)
FILE *stream;
long num;
float sbuff[];
This routine works like putslice except that a slice is written in ascii format. The data are expected in float form in sbuff. Pixel fields are written in hexidecimal form, one byte at a time.
creating and modifying header buffers:
nullhdr(buffer,max,format)
char buffer[][LINE],*format;
int max;
The normal procedure for creating common data format headers from scratch is to generate a null header using this routine, and then add comments, parameters, and field lines by line using the routines that follow. Buffer is a character array allocated by the calling routine into which the null header is placed. Max is the number of lines in buffer. (Note that a parameter HBMAX is defined in cdfhdr.h, which defines a reasonable upper bound to the number of lines required in a header. This value of max is used in many common data format filters.) Format should be "float", "int", or "ascii", depending on the required data format.
copycmt(hbnew,maxnew,hbold,maxold)
char hbnew[][LINE],hbold[][LINE];
int maxnew,maxold;
This routine appends the entire comment section from the header buffer hbold to the header buffer hbnew’s comment section. The parameters maxnew and maxold are the maximum numbers of lines for the respective buffers. (Typically, HBMAX is used here.)
copypar(hbnew,maxnew,hbold,maxold)
char hbnew[][LINE],hbold[][LINE];
int maxnew,maxold;
This routine appends the parameter section of the header buffer hbold onto that of hbnew. The parameters maxnew and maxold are the maximum numbers of lines for the respective buffers. (Typically, HBMAX is used here.)
copyfld(hbnew,maxnew,hbold,maxold,type)
char hbnew[][LINE],hbold[][LINE];
char type;
int maxnew,maxold;
This routine appends the field definitions from the header buffer hbold onto those of hbnew. If type = ’s’, then the static slice definitions are copied, whereas type = ’v’ copies the variable slice definitions. The parameters maxnew and maxold are the maximum numbers of lines for the respective buffers. (Typically, HBMAX is used here.)
addcline(buffer,max,cline)
char buffer[][LINE],*cline;
int max;
This routine appends a comment line to the end of any existing comments in buffer. The comment line is contained in the string cline, and must have a newline as the last non−null character. If the header tries to grow to more than max lines, addcline complains and dies.
addcommand(argc,argv,buffer)
int argc;
char *argv[];
char buffer[][LINE];
This routine adds the command line to a header buffer. The command line is broken into rows of less than LINE characters. Lines are only broken at whitespace, unless there is none. These are added to the header comment, with each line after the first being indented 2 spaces.
addpar(buffer,max,pname,pval)
char buffer[][LINE],*pname,*pval;
int max;
This routine appends a parameter and its value to the parameter section of a header buffer. These are respectively contained in the strings pname and pval. If buffer tries to grow to more than max lines, addpar complains and dies.
addfld(buffer,max,type,fname,smul,sadd,precision,dim,d1,n1,d2,n2,d3,n3,d4,n4)
char buffer[][LINE],type,precision,*fname,*d1,d2,d3,d4;
float smul,sadd;
int max,dim,n1,n2,n3,n4;
This routine appends a field description to either the static (type = ’s’) or the variable (type = ’v’) section of a header buffer. If buffer tries to grow to more than max lines, addfld complains and dies. Fname is a string that contains the name of the field. Smul and sadd are the scaling parameters for conversion to and from int format (see CDF(5)), and precision specifies the number of integer bytes used in this conversion. Precision = ’c’ indicates char, or 1 byte, ’s’ indicates short, or 2 bytes, and ’l’ indicates long, or 4 bytes. (The actual number of bytes may vary with the computer.) The number of dimensions to the field is specified by dim, and may be 0, 1, 2, 3, or 4. D1, d2, d3, and d4 are strings that name the dimensions, while n1, n2, n3, and n4 specify how big they are. Inclusion of arguments containing dimension names and sizes in excess of that required by dim is optional.
interpreting common data format header buffers:
getcmt(buffer,max,comment)
int max;
char buffer[][LINE],comment[][LINE];
This routine extracts the comment from a common data format header that has been read into buffer by gethdr, or otherwise created. Max is the size of buffer in lines, and is passed only to prevent wild excursions through memory in the event of a badly formed header. The comment is placed in comment, and the routine returns the number of comment lines. No provision is made to check for overflow in comment, so it is safest to allocate as many lines in comment as there are in buffer.
getpar(buffer,max,pos,pname,value)
int pos,max;
char buffer[][LINE],*pname,*value;
This routine extracts the pos’th parameter (starting from zero) from a common data format header that has been read into buffer by gethdr. Max is the size of buffer in lines. The parameter name and value are respectively placed in the strings pname and value. If a parameter is found in the pos’th position, getpar returns OK. Otherwise, it returns FAIL, i. e., if there are less than pos + 1 parameters in the header.
seekpar(buffer,max,pname,value)
int max;
char buffer[][LINE],*pname,*value;
This routine works the same as getpar, except that the parameter is sought by name rather than position. Pname is this input rather than output. If a parameter with the specified name is found, OK is returned, and the value is placed in the string value. Otherwise FAIL is returned.
struct field
*getfld(buffer,max,type,pos)
int max,pos;
char buffer[][LINE],type;
This routine extracts a description of the pos’th field (starting from zero) from either the static field (type = ’s’) or the variable field (type = ’v’) section of a common data format header that has been read into buffer by gethdr. Max is the size of buffer in lines. Getfld returns a pointer to a field structure containing information about the field. Storage for this is internal to getfld, so subsequent calls to getfld will overwrite the previous field information. (See the description of the field structure in cdfhdr.h, reproduced below.) If no field is found in position pos, getfld returns NULL.
struct field
*seekfld(buffer,max,type,fname)
int max;
char buffer[][LINE],type,*fname;
This routine works like getfld except that fields are extracted by name (fname) rather than position in the header. NULL is returned if no field by the specified name is found.
char
getfmt(buffer,max)
char buffer[][LINE];
int max;
This routine returns the format specified in a common data format header that has been read into buffer by gethdr. Max is the size of the buffer in lines. For float format, ’f’ is returned, while ’a’ and ’i’ are respectively returned for ascii and packed integer formats.
long
elemcnt(buffer,max,type)
char buffer[][LINE],type;
int max;
This routine examines either the static field (type = ’s’) or variable field (type = ’v’) section of a common data format header that has been read into buffer by gethdr. It returns the number of elements to be expected in static or variable slices. Max, as always, is the size of buffer in lines.
getilist(buffer,max,type,size,length,offset,add,mul)
char buffer[][LINE];
int max;
char type;
int *size;
long *length,*offset;
float *add,*mul;
This routine extracts information from a header buffer for the purpose of converting slice data to or from int format. Buffer is the desired header buffer, max is the maximum allowed size of the buffer, and type is ’s’ or ’v’, depending on whether information about static or variable slices is desired. Information is returned about the fields in the specified slice type in the arrays size, length, offset, add, and mul. The size of pixel fields is set to minus the length of a float by this routine. These should be allocated by the calling routine, and should be of minimum length equal to the number of variables in the desired slice plus one. A safe value is max.
managing common data format slice buffers:
float
*getbuff(nelem)
long nelem;
This routine allocates a slice buffer of nelem elements using the malloc function. If the requested memory is unavailable, the routine dies with an error message. If successful, a pointer to the buffer is returned.
float
*getptr(hbuff,max,sbuff,type,failmode,fname)
char hbuff[][LINE],type,failmode,*fname;
int max;
float *sbuff;
This routine returns a pointer to a field, given its name fname, the header buffer hbuff in which it is defined, whether it is a static or variable field (type = ’s’ or ’v’), and the slice buffer sbuff in which it is located. (Sbuff must have been previously allocated.) If the the desired field can’t be found in the requested header buffer, getptr fails in a manner defined by the value of failmode. If failmode = ’d’, getptr dies with an error message. If failmode = ’r’, NULL is returned. Max is the maximum number of lines in the header buffer.
float
*getptr2(hbuff,max,sbuff,type,failmode,fname,&fstructptr)
char hbuff[][LINE],type,failmode,*fname;
int max;
float *sbuff;
struct field *fstructptr;
This routine works precisely like getptr except that in addition a pointer to the field structure of the specified variable is returned. The last argument should specify the address of this pointer. The structure data are in dynamically allocated memory, so that repeated calls to getptr2 won’t overwrite previous data. Use getptr2 when more information than just the address is needed about a particular variable.
subspace1(fp,dname,instance,start,incr,size)
struct field *fp;
char *dname;
long instance;
long *start,*incr,*size;
This routine returns loop variables to access a particular instance of a one−dimensional sub−space of a multi−dimensional field. The desired dimension name is given by "dname", and "fp" is a pointer to a field structure containing information on the field of interest. The contents of fp are typically generated by getptr2. "Start", "incr", and "size" are respectively pointers to loop variables, and elements of the sub−space are typically accessed as follows:
for (loop = 0; loop < *size; loop++) {
element = field_pointer[*start + *incr * loop] ...
Different instances of the sub−space are accessed by setting "instance" to 0, 1, 2, ... until subspace1 returns FAIL. "Field_pointer" is a pointer to the field, such as is returned by getptr2.
floatswap(n,buff)
long n;
float *buff;
This routine reverses the byte order in the floats in the array "buff", which is of length "n".
A sample version of cdfhdr.h is included here for the convenience of programmers. Be sure to examine the version on your own system to check the values of parameters, as these may change from system to system.