Actual C code to read in a single plane

This is the actual C code4 to read in a plane file. The function read_plane takes as arguments a pointer to a pointer to a PLANE structure, a pointer to a pointer to a PLANE_INFO structure, a pointer to a string pointer, and a string pointer. This function allocates space (via malloc() and calloc()) for the PLANE, the PLANE_INFO, and the associations list and it side-affects its first three arguments, which should be either addresses of variables or array or structure slots. read_plane returns -1 on error and the value of the multi_plane_flag on success.

#define BLOCKSIZE 512 /* max number of bytes to read at a time */

 /*
  * read_plane(plane,plane_info,associations,filename) - read
  * in a plane file. plane is a pointer to a pointer to a 
  * PLANE object, plane_info is a pointer to a pointer to a 
  * PLANE_INFO object, associations is a pointer to a pointer
  * to char, and filename is a pointer to a char.
  * plane, plane_info, and associations are set to malloc'ed
  * space, so should be addresses of cloberable pointers (i.e.
  * addresses of variables or structure fields, etc.).
  */

read_plane(plane,plane_info,associations,filename)
PLANE **plane;
PLANE_INFO **plane_info;
char **associations;
char *filename;
{

First we declare local variables:

    /* plane file header record structure */
    static LLVS_PLANE_FILE_HEADER header;
    /* plane size header record structure */
    static LLVS_PLANE_SIZE_HEADER size_header;
    int plsize;                 /* # bytes in plane */
    FILE *plfile;               /* plane file */
    llvs_ubyte *data_pointer; /* pointer to data buffer */
    int rbytes, bytesleft;      /* I/O byte counters */
    int need_swap, need_cvt_float; /* flags to indicate if
                                      conversions needed */

Now we open the plane file and read in the plane file header record:

    /* open file.  abort if open failure */
    plfile = fopen(filename,"r");
    if (plfile == NULL) return(-1);
    /* read header record */
    if (fread(&header,32,1,plfile) != 1) return(-1);

Next we generate the conversion flags. LLVS_NATIVE_BYTE_SEX and LLVS_NATIVE_FLOATFMT are macros defined in llvs_plane.h under control of contitional compilation macros defining the machine type (i.e. VAX, SUN, or SEQUENT, etc.).

    need_swap = header.bsex != LLVS_NATIVE_BYTE_SEX;
    need_cvt_float = header.floatfmt != LLVS_NATIVE_FLOATFMT;

Now we convert the remainder of the header to native internal storage format:

    if (need_swap) swap_longs(&header.pl_level,7);
    if (header.ptype == LLVS_PLF_FLOAT && need_cvt_float) 
        cvt_floats(&header.background,1,header.floatfmt,
                   LLVS_NATIVE_FLOATFMT);

Now we compute the size of the plane in bytes, allocate the PLANE_INFO structure, fill in the PLANE_INFO structure, and allocate memory for the plane itself.

    /* compute plane size */
    plsize = header.data_length - 12;
    /* allocate plane info struct */
    *plane_info = (PLANE_INFO *) malloc(sizeof(PLANE_INFO));
    if (*plane_info == NULL) return(-1);
    /* fill in plane info slots */
    (*plane_info)->datatype = header.ptype;
    (*plane_info)->level = header.pl_level;
    (*plane_info)->row_location = header.row_location;
    (*plane_info)->column_location = header.col_location;
    (*plane_info)->background.fixnum = 
        header.background.iback;
    /* allocate plane it self */
    *plane = (PLANE *) malloc(plsize);
    if (*plane == NULL) return(-1);

Now we allocate space for the associations list and read in the associations list record. This C function does not actually do anything with the associations list. In the Common LISP based system, we pass this string to the Common LISP function READ-FROM-STRING and can then access the association list with Common LISP association list access functions.

    /* allocate space for association list */
    *associations = calloc(header.alist_length+1,
                           sizeof(char));
    if (*associations == NULL) return(-1);
    /* read in association list */
    data_pointer = (llvs_ubyte *) *associations; /* start of
                                                    buffer */
    bytesleft = header.alist_length; /* number of bytes to
                                        read */
    while (bytesleft > 0) {
        rbytes = bytesleft;
        if (rbytes > BLOCKSIZE) rbytes = BLOCKSIZE;
        if (fread(data_pointer,rbytes,1,plfile) != 1) 
            return(-1);
        data_pointer += rbytes;
        bytesleft -= rbytes;
        }

Now we read in and convert the size header and fill in the plane dimension info.

    /* read size header */
    if (fread(&size_header,12,1,plfile) != 1) return(-1);
    if (need_swap) swap_longs(&size_header,3);
    /* fill in addition slots in plane info */
    (*plane_info)->row_dimension = size_header.row_dimension;
    (*plane_info)->column_dimension = 
        size_header.col_dimension;

Finally, we read in the plane data itself, converting the data as we go.

    /* read in plane */
    data_pointer = (unsigned char *) (*plane)->plane_base;
    bytesleft = plsize;
    while (bytesleft > 0) {
        rbytes = bytesleft;
        if (rbytes > BLOCKSIZE) rbytes = BLOCKSIZE;
        if (fread(data_pointer,rbytes,1,plfile) != 1) 
            return(-1);
        if (need_swap && header.ptype == LLVS_PLF_SHORT) 
            swap_words(data_pointer,rbytes >> 1);
        if (need_swap && (header.ptype == LLVS_PLF_INT || 
                          header.ptype == LLVS_PLF_FLOAT))
            swap_longs(data_pointer,rbytes >> 2);
        if (need_cvt_float && header.ptype == LLVS_PLF_FLOAT)
            cvt_floats(data_pointer,rbytes >> 2,
                       header.floatfmt,LLVS_NATIVE_FLOATFMT);
        data_pointer += rbytes;
        bytesleft -= rbytes;
        }

When we are done, we close the file. Read_plane returns the value of the multi-plane flag. This will be zero if this file contained only one plane or a positive non-zero value indicating the number of additional planes in the file. Read_plane returns -1 when it encountes a system error (I/O error or a memory allocation failure).

    /* close file */
    fclose(plfile);
    return(header.multi_plane_flag);
    }

=5000

There are 3 conversion functions used by this function: swap_longs(), swap_words(), and cvt_floats(). These three functions are defined in read_write_plane.c. The first two functions do byte swaping on long ints and short ints and the third function converts floating point formats. All three functions modify the memory pointed at by their first argument. The second argument is the count of elelemts to convert. cvt_floats has two additional arguments: the current format of the floating point numbers and the desired (i.e. native) floating point format.

=