4.3BSD/usr/contrib/dipress/src/lib/libip/literal.c

Compare this file to the similar file:
Show the results in this format:

/*
 *  Interpress utilities
 *
 *  Written for Xerox Corporation by William LeFebvre
 *  24-May-1984
 *
 * Copyright (c) 1984, 1985 Xerox Corp.
 *
 * HISTORY
 * 15-Jan-86  lee at Xerox, WRC
 *	Removed the rest of the Vax dependencies.
 *
 *	10-sep-85  lee moore	Removed some dependencies on the Vax.
 *				Plenty more to be removed
 *	29-apr-85  ed flint	add conditional compilation for vax-11 c (vms)
 */

/*
 *  Subroutines to help build interpress files:
 *
 *  literal interface level - these routines produce interpress output at
 *			      the token level.
 */

/*
 *  NOTE:  Some of these "subroutines" are one-liners, so they are written
 *	   as macros for better efficiency.
 */

# define Rational_max	1073741824
# define ip_Buffsize	1024

#ifndef vax11c
# include <sys/param.h>
# include <math.h>
# include <stdio.h>
#endif

# include "iptokens.h"
# include "literal.h"		/* macro definitions for some routines */

# ifndef NULL
# define NULL (char *)0
# endif

#ifdef vax11c
# define NOFILE 20
#endif

# define   No	0
# define   Yes	1

static int  ip_fd = -1;			/* current Interpress file */
static char ip_filebuff[ip_Buffsize];	/* file buffer */
static char *ip_buffptr = NULL;		/* points in to ip_filebuff */
static int  ip_bytecnt;			/* number of bytes in ip_filebuff */
static char ip_files[NOFILE] = { 0 };	/* marks which files are ip files */

/*
 *  Definitions for the primitives suggested in the Interpress standard
 *  (XSIS 048302).  The following primitives are defined with macros in
 *  "literal.h":
 *
 *	AppendComment
 *	AppendIdentifier
 *	AppendInsertFile
 *	AppendString
 *
 *  Currently, AppendString will only handle byte values -- it will not
 *  try to insert any escape characters.  The rationale for this is that
 *  ASCII (which is what this system uses) doesn't have character codes that
 *  high.
 */

AppendOp(opcode)

int opcode;

{
    if (opcode > SHORT_OP_LIMIT)
    {
	/* has to be coded as a long op */
	append_word((unsigned short)((LONG_OP << 8) | opcode));
    }
    else
    {
	/* small enough to be a short op */
	append_byte((unsigned char)(SHORT_OP | opcode));
    }
}

AppendNumber(number)

double number;

{
    long d;
    double r;
    
    if (number == (double)(d = (long)number))
    {
	AppendInteger(d);
    }
    else
    {
	d = 1;
	while ((fabs(r = number * d) < Rational_max) &&
	       (d < Rational_max) &&
	       (r != (float)((int)(r))))
	{
	    d <<= 1;
	}
	AppendRational((long)r, d);
    }
}


/*
 * note that although the routine is called AppendInteger, it is really
 * AppendLong.  This is because alot of code wants to use 32 bit numbers.
 * If you want to pass it a 16bit int, that will work too.
 */

AppendInteger(number)

long number;

{
    if (number < INTEGER_MIN || number > INTEGER_MAX)
    {
	append_integer_sequence(number);
    }
    else
    {
	append_short_number((short) number);
    }
}

AppendRational(value, divisor)

long value, divisor;

{
    int len_value, len_divisor, len;

    len_value = bytes_in_int(value);
    len_divisor = bytes_in_int(divisor);

    len = len_value > len_divisor ? len_value : len_divisor;
    append_Sequence(sequenceRational, len << 1, (unsigned char *)NULL);
    append_n_byte_int(value, len);
    append_n_byte_int(divisor, len);
}

#ifdef notdef
AppendIntegerVector(vector, num)

int *vector;	/* ??? */
int  number;

{
    
}
#endif

/*
 *  The remainder of this file contains lower level primitives:
 */

/*
 *  append_Sequence(type, length, buff)
 *
 *  Append a sequence descriptor and its data bytes.  The descriptor is of
 *  type "type" and length "length".  "Buff" points to the buffer containing
 *  the data.  If "length" is negative, then bytes from "buffer" are written
 *  back to front (this makes writing integers easy).
 */

append_Sequence(type, length, buff)

int  type;
int  length;
unsigned char *buff;

{
# ifdef notnow
    /* some day, we should make this check, but not today */
    if ((length & 0x7f000000) != 0)
    {
	/* too big to fit in a long ... */
    }
# endif

    /* check for swapped byte correction */
    if (length < 0)
    {
	fprintf(stderr, "negative sequence!\n");
	abort();
    }

    if ((length & 0x7fffff00) != 0)
    {
	/* too big to fit in a short sequence */
	append_byte((unsigned char) (LONG_SEQUENCE | type));
	append_n_byte_int((long) length, 3);
    }
    else
    {
	append_byte((unsigned char) (SHORT_SEQUENCE | type));
	append_byte((unsigned char) length);
    }

    /* tack on data, if any */
    if (buff != NULL)
        append_bytes(length, buff);
}


/*
 * append_integer_sequence(number)
 *	A special version of append_sequence that handles integers.  Integers
 *	must be treated differently because the natural representation of an
 *	integer for a particular machine maybe byte swapped relative to the
 *	Xerox standard.
 */
append_integer_sequence(number)

long number;

{
    int length = bytes_in_int(number);

    append_byte((unsigned char) (SHORT_SEQUENCE | sequenceInteger));
    append_byte((unsigned char) length);
    append_n_byte_int(number, length);
}

/*
 * append_n_byte_int(number, length)
 *	Append N bytes of an integer to the interpress master.
 */

append_n_byte_int(number, length)

long number;
int length;	/* measured in bytes */

{
    int shift;

#ifdef notdef
    switch( length ) {
	case 4:
		append_byte((unsigned char) (number >> 24));
	case 3:
		append_byte((unsigned char) (number >> 16));
	case 2:
		append_byte((unsigned char) (number >>  8));
	case 1:
		append_byte((unsigned char) number);
		break;
	default:
		fprintf(stderr, "append_n_byte_int: asked to append %d bytes\n", length);
	}
#else
    if( length > sizeof(long) )
	fprintf(stderr, "append_n_byte_int: asked to append %d bytes\n", length);

    for( shift = (length - 1)*8; shift >= 0; shift -= 8 )
	append_byte((unsigned char) (number >> shift));
#endif
}
	

/*
 *  append_word(value) - write the two byte (word) value "value"
 */

append_word(value)

unsigned short value;

{
#ifdef notdef
    append_n_byte_int(value, 2);
#else
    append_byte((unsigned char) (value >> 8));
    append_byte((unsigned char) value);
#endif
}

/*
 *  append_byte(value) - write out a byte
 */

append_byte(value)

unsigned char value;

{
    *ip_buffptr++ = value;
    if (++ip_bytecnt == ip_Buffsize)
    {
	write(ip_fd, ip_filebuff, ip_Buffsize);
	ip_bytecnt = 0;
	ip_buffptr = ip_filebuff;
    }
}

/*
 *  append_bytes(length, buff) - write the buffer of bytes pointed to by
 *				 "buff" with length "length".
 */

append_bytes(length, buff)

int length;
unsigned char *buff;

{
    while (length-- > 0)
    {
	append_byte(*buff++);
    }
}


/* this routine assumes 4 bytes in an int and two's complement notation */
/* this routine should be replaced! -lee */
/* this routine sometime over estimates the size of an integer. why? */

bytes_in_int(value)

long value;

{
    int i;
    long mask;

    if (value < 0)
    {
	/* takes the same space as its one's complemented value */
	value = ~value;
    }
    if (value == 0)
    {
	/* avoids infinite looping */
	return(1);
    }
    for (i = 4, mask = 0xff800000; (value & mask) == 0; i--, mask >>= 8)
	;
    return(i);
}

/*
 *  ip_select(fd) - select file descriptor "fd" as the Interpress file for
 *		    later use by the i/o routines supplied in this library.
 */

ip_select(fd)

int fd;

{
    if (ip_fd != -1)
    {
	ip_flush();
    }

    /* set our idea of current file descriptor and initialize the buffer */
    ip_fd = fd;
    ip_buffptr = ip_filebuff;
    ip_bytecnt = 0;

    /* check for initialization */
    if (!ip_files[fd])
    {
	/* not an Intepress file -- initialize it */
	append_bytes(strlen(IP_Header), (unsigned char *) IP_Header);
	ip_files[fd] = Yes;
    }
}

/*
 *  ip_raw_select(fd) - same as ip_select, but no header is placed at the
 *			front of the file.
 */

ip_raw_select(fd)

int fd;

{
    /* trick ip_select into thinking that it is already initialized */
    ip_files[fd] = Yes;

    /* do a normal select */
    ip_select(fd);
}

ip_close()

{
    if (ip_fd != -1)
    {
	ip_flush();
	ip_files[ip_fd] = No;
	close(ip_fd);
	ip_fd = -1;
    }
}

ip_flush()

{
    /* flush the buffer */
    if (ip_Buffsize - ip_bytecnt > 0)
    {
	write(ip_fd, ip_filebuff, ip_bytecnt);
    }
}