Listing 2 Long Transfer Functions

/* Copyright (C) 1994 James A. Kuzdrall
  Free license to this software is granted only if the above
  copyright credit is included in the source code */

/* ***< LNGTXF.CEE   >***

  /* put system headers here */
#include  <stdio.h>    /* usual definitions */

  /* use limit if does not exceed range of host machine */
#define MAXLNG 2147483647L   /* limit +2147483647 */
#define MINLNG -2147483648L  /* limit -2147483648 */
#define XFER_ERROR -1        /* a non-zero integer */

/***< fputl     >*** ++++++++++++++++++++++++++++++++++++++++++++++ *

  USE....... Convert host's long integer to the 4-byte, 2's comple-
    ment, MSB-first standard transfer format. Send the four bytes
    to the output stream fp.
  RETURNS... Non-zero if error; otherwise, 0
    No number sent if error.
  ERRORS.... Disk errors of putc().
    Overrange if exceeds transfer range, 2147483647 to -2147483648.
*/

int  fputl(lp,fp)
  long  *lp;       /* long to put on disk */
  FILE  *fp;       /* file pointer given by fopen() */
  {
  int   ix;          /* byte counter */
  long  absl:       /* absolute value of *lp */
  unsigned int   byt[5];   /* byt[0] is most significant */
  int   err;

  if( MINLNG != -2147483647   &&  *lp == MINLNG ) {
    byt[0]= 0x80;   /* set 2's complement -2147483648 */
    byt[1]=byt[2]=byt[3]=0
    }
  else {
    /* avoid problem with -MINLNG in 2's comp, 4-byte */
    absl= (*lp <= -1L  &&  *lp >= -2147483647) ? -*lp : *lp;

    /* divide magnitude into bytes; if neg, negate in 2's comp */
    byt[4]= 0x100;                   /* becomes 1 after >> 8 */
    for( ix= 3; ix >= 0; ix-- ) {    /* process from LSB to MSB */
      byt[ix]= (absl >> (8*(3-ix))) & 0xff;
      if( *lp <= -1L )
        byt[ix]= (byt[ix] ^ 0xff) + (byt[ix+1] >> 8);
      }
    }
  err= XFER_ERROR;                    /* preset */
  /* if in range, send MSB first */
  if( *lp <= MAXLNG  &&  (*lp >= -2147483647 || *lp == MINLNG) ) {
    for( ix= 0; ix < 4; ix++ )
      if( putc(byt[ix],fp) == EOF )
        goto plxit;
    err=0;
    }
  plxit:
  return( err );
  }

/***< fgetl     >*** +++++++++++++++++++++++++++++++++++++++++++++++*

  USE....... Read a standard format, 4-byte long integer from the
    input stream fp and convert it to the host's long format.
  RETURNS...  ERROR if error; otherwise, 0
    Places answer at pointer if no errors.
  ERRORS.... From getc() only; generates no errors of its own.
*/

int  fgetl(lp,fp)
  long  *lp;       /* place where answer goes */
  FILE  *fp;       /* file pointer given by fopen() */
  {
  int   ix;        /* byte counter */
  char  neg;       /* non-zero (true) if original nr was negative */
  long  ans;       /* temporary */
  unsigned int  byt[5]; /* byt[0] is most significant */
  int   err;

  err: XFER_ERROR;               /* preset */
  for( ix= 0; ix<4; ix++ ) {     /* byte read from MSB to LSB */
    if( (byt[ix]= getc(fp)) == EOF )
      goto glxit;
    byt[ix] &= 0xff;            /* remove any high bits */
    }

  /* detect special case, -2147483648 in non-2's complement host */
  if( MINLNG == -2147483647 && byt[0] == 0x80 && !byt[1] &&
      !byt[2] &&  !byt[3] )
    goto glxit;    /* out-of-range error */
  err= 0;                         /* no error */

  ans= 0L;
  byt[4]= 0x100;                  /* becomes 1 after >> 8 */
  neg= byt[0] & 0x80;
  for( ix= 3; ix >= 0; ix-- ) {
    if( neg )  /* make negative nrs positive by 2's comp negate */
      byt[ix]= (byt[ix] ^ 0xff) + (byt[ix+1] >> 8);
    ans |= ((long)(byt[ix] & 0xff)) << 8*(3-ix);
    }

  /* handle MINLNG separately; has negate and range problems */
  if( byt[0] & 0x80 )              /* only MINLNG is still neg */
    *lp= MINLNG;
  else                             /* for all but MINLNG /*
    *lp= neg ? -ans : ans;         /* let host install sign */

  glxit:
  return( err );
  }
/* End of File */