/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is 
 * preserved on all copies.
 * 
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the 
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 *
 *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
 *  to have all "void" functions so declared.
 */
/* 
 * rle_row_alc.c - Allocate buffers for rle_getrow/rle_putrow.
 * 
 * Author:	Spencer W. Thomas
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	Fri Nov 14 1986
 * Copyright (c) 1986, Spencer W. Thomas
 */

#include <stdio.h>
#include <malloc.h>
#include "rle_put.h"

#include "raddecl.h"

/*****************************************************************
 * TAG( rle_row_alloc )
 * 
 * Allocate buffer space for use by rle_getrow and rle_putrow.
 * Inputs:
 * 	the_hdr:	Header structure for RLE file to be read or
 *			written.
 * Outputs:
 *	scanp:		Pointer to pointer to created scanline buffer.
 *			This pointer is adjusted for the alpha channel,
 *			if present.
 *	Returns 0 for success, -1 if malloc failed.
 * Assumptions:
 * 	No input scanline will extend beyond the declared xmax endpoint.
 * Algorithm:
 *	Count number of channels actually used (check bitmap).
 * 	Allocate nchan*rowlength pixels, allocate a buffer
 *	to hold ncolors+alpha pointers, and give each channel
 *	rowlength pixels.  Rowlength is xmax + 1, to allow for rle_getrow
 *	usage.
 */
int rle_row_alloc( the_hdr, scanp )
rle_hdr *the_hdr;
rle_pixel ***scanp;
{
    rle_pixel ** scanbuf, * pixbuf;
    int rowlen, nchan = 0, i, ncol;

    rowlen = the_hdr->xmax + 1;
    if ( the_hdr->alpha && RLE_BIT( *the_hdr, RLE_ALPHA ) )
	nchan++;
    for ( i = 0; i < the_hdr->ncolors; i++ )
	if ( RLE_BIT( *the_hdr, i ) )
	     nchan++;

    ncol = the_hdr->ncolors + the_hdr->alpha;

    if ( (scanbuf = (rle_pixel **)malloc( ncol * sizeof(rle_pixel *) )) == 0 )
	return -1;
    if ( (pixbuf = (rle_pixel *)malloc( nchan * rowlen *
				       sizeof(rle_pixel) )) == 0 )
    {
	free( scanbuf );
	return -1;
    }

    if ( the_hdr->alpha )
	scanbuf++;

    for ( i = -the_hdr->alpha; i < the_hdr->ncolors; i++ )
	if ( RLE_BIT( *the_hdr, i ) )
	{
	    scanbuf[i] = pixbuf;
	    pixbuf += rowlen;
	}
	else
	    scanbuf[i] = 0;
    *scanp = scanbuf;

    return 0;
}


/*****************************************************************
 * TAG( rle_row_free )
 * 
 * Free storage allocated by rle_row_alloc().
 * Inputs:
 * 	the_hdr:	Header structure as above.
 *	scanp:		Pointer to scanbuf above.
 * Outputs:
 * 	Frees storage referenced by scanp and nrawp.
 * Assumptions:
 * 	Storage was allocated by rle_row_alloc, or by use of same
 *	algorithm, at least.
 * Algorithm:
 * 	free scanp[0] and scanp.
 */
void rle_row_free( the_hdr, scanp )
rle_hdr *the_hdr;
rle_pixel **scanp;
{
    int i;

    if ( the_hdr->alpha )
	scanp--;
    for ( i = 0; i < the_hdr->ncolors + the_hdr->alpha; i++ )
	if ( scanp[i] != 0 )
	{
	    free( (char *)scanp[i] );
	    break;
	}
    free( (char *)scanp );
}
/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is 
 * preserved on all copies.
 * 
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the 
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 *
 *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
 *  to have all "void" functions so declared.
 */
/* 
 * rle_putrow.c - Save a row of the fb to a file.
 * 
 * Author:	Spencer W. Thomas
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	1 April 1981
 * Copyright (c) 1981,1986 Spencer W. Thomas
 *
 * $Id: rle_putrow.c,v 3.0.1.1 90/11/27 14:54:37 spencer Exp $
 */
 
#ifdef USE_STDLIB_H
#include <stdlib.h>
#else

#endif /* USE_STDLIB_H */

static int findruns();

#define FASTRUNS		/* Faster run finding */
#ifdef vax
#define LOCC			/* Use vax instructions for more speed */
#endif

#define	FALSE	0
#define	TRUE	1

/*****************************************************************
 * TAG( rle_putrow )
 * Write a scanline to the output file.
 * 
 * Inputs:
 *	rows:		Pointer to vector of pointers to
 *			rle_pixel arrays containing the pixel information.
 *			If NULL, rowlen scanlines are skipped.
 *	rowlen:		The number of pixels in the scanline, or the
 *			number of scanlines to skip (see above).
 * Outputs:
 * 	Run length encoded information is written to the_hdr.rle_file.
 * Assumptions:
 * 	I'm sure there are lots of assumptions in here.
 * Algorithm:
 * 	[read the code :-]
 */

void rle_putrow(rows, rowlen, the_hdr)
register rle_pixel *rows[];
int rowlen;
register rle_hdr * the_hdr;
{
    register int i, j;
    int nrun;
    register rle_pixel *row;
    int mask;
    char bits[256];
    short   state,
	    dstart,
    	    dend,
	    rstart = 0,
	    runval = 0;			/* shut up lint */

    if (rows == NULL)
    {
	the_hdr->priv.put.nblank += rowlen;
	return;
    }
    /* 
     * If not done already, allocate space to remember runs of
     * non-background color.  A run of bg color must be at least 2
     * bytes long to count, so there can be at most rowlen/3 of them.
     */
    if ( the_hdr->priv.put.brun == NULL )
    {
	the_hdr->priv.put.brun =
	    (short (*)[2])malloc(
		(unsigned)((rowlen/3 + 1) * 2 * sizeof(short)) );
	if ( the_hdr->priv.put.brun == NULL )
	{
	    fprintf( stderr, "Malloc failed in rle_putrow\n" );
		exit(1);
	}
    }
    /* Unpack bitmask in the_hdr struct */
    for ( i=0; i < the_hdr->ncolors; i++ )
	bits[i] = RLE_BIT( *the_hdr, i );
    bits[255] = RLE_BIT( *the_hdr, -1 );

    /* 
     * If saving only non-background pixels, find runs of them.  Note
     * that the alpha channel is considered to be background iff it is
     * zero.
     */
#ifdef	FASTRUNS
    if ( the_hdr->background )
    {
	/* 
	 * Find runs in each color individually, merging them as we go.
	 */
	nrun = 0;		/* start out with no runs */
	/* Alpha channel first */
	if ( the_hdr->alpha )
	    nrun = findruns( rows[-1], rowlen, 0, nrun,
			    the_hdr->priv.put.brun );
	/* Now the color channels */
	for ( i = 0; i < the_hdr->ncolors; i++ )
	    if ( bits[i] )
		nrun = findruns( rows[i], rowlen, the_hdr->bg_color[i],
				 nrun, the_hdr->priv.put.brun );
    }
    else
    {
	the_hdr->priv.put.brun[0][0] = 0;
	the_hdr->priv.put.brun[0][1] = rowlen-1;
	nrun = 1;
    }
#else				/* FASTRUNS */
    if (the_hdr->background)	/* find non-background runs */
    {
	j = 0;
	for (i=0; i<rowlen; i++)
	    if (!same_color( i, rows, the_hdr->bg_color,
			     the_hdr->ncolors, bits ) ||
		(the_hdr->alpha && rows[-1][i] != 0))
	    {
		if (j > 0 && i - the_hdr->priv.put.brun[j-1][1] <= 4)
		    j--;
		else
		    the_hdr->priv.put.brun[j][0] = i; /* start of run */
		for ( i++;
		      i < rowlen && 
			( !same_color( i, rows, the_hdr->bg_color,
					 the_hdr->ncolors, bits ) ||
			  (the_hdr->alpha && rows[-1][i] != 0) );
		      i++)
		    ;			/* find the end of this run */
		the_hdr->priv.put.brun[j][1] = i-1;    /* last in run */
		j++;
	    }
	nrun = j;
    }
    else
    {
	the_hdr->priv.put.brun[0][0] = 0;
	the_hdr->priv.put.brun[0][1] = rowlen-1;
	nrun = 1;
    }
#endif				/* FASTRUNS */
    if (nrun > 0)
    {
	if (the_hdr->priv.put.nblank > 0)
	{
	    SkipBlankLines(the_hdr->priv.put.nblank);
	    the_hdr->priv.put.nblank = 0;
	}
	for ( mask = (the_hdr->alpha ? -1 : 0);
	      mask < the_hdr->ncolors;
	      mask++)			/* do all colors */
	{
	    if ( ! bits[mask & 0xff] )
	    {
		continue;
	    }
	    row = rows[mask];
	    SetColor(mask);
	    if (the_hdr->priv.put.brun[0][0] > 0)
	    {
		SkipPixels(the_hdr->priv.put.brun[0][0], FALSE, FALSE);
	    }
	    for (j=0; j<nrun; j++)
	    {
		state = DATA;
		dstart = the_hdr->priv.put.brun[j][0];
		dend = the_hdr->priv.put.brun[j][1];
		for (i=dstart; i<=dend; i++)
		{
		    switch(state)
		    {
		    case DATA:
			if (i > dstart && runval == row[i])
			{
			    state = RUN2;	/* 2 in a row, may be a run */
			}
			else
			{
			    runval = row[i];	/* maybe a run starts here? */
			    rstart = i;
			}
			break;
	    
		    case RUN2:
			if (runval == row[i])
			{
			    state  = RUN3;	/* 3 in a row may be a run */
			}
			else
			{
			    state = DATA;	/* Nope, back to data */
			    runval = row[i];	/* but maybe a new run here? */
			    rstart = i;
			}
			break;

		    case RUN3:
			if (runval == row[i])	/* 3 in a row is a run */
			{
			    state = INRUN;
			    putdata(row + dstart, rstart - dstart);
#ifdef FASTRUNS
#ifdef LOCC
			    /* Shortcut to find end of run! */
			    i = dend - skpc( (char *)row + i, dend + 1 - i,
					     runval );
#else
			    while ( row[++i] == runval && i <= dend)
				; /* not quite so good, but not bad */
			    i--;
#endif /* LOCC */
#endif /* FASTRUNS */
			}
			else
			{
			    state = DATA;		/* not a run, */
			    runval = row[i];	/* but may this starts one */
			    rstart = i;
			}
			break;
	    
		    case INRUN:
			if (runval != row[i])	/* if run out */
			{
			    state = DATA;
			    putrun(runval, i - rstart, FALSE);
			    runval = row[i];	/* who knows, might be more */
			    rstart = i;
			    dstart = i;	/* starting a new 'data' run */
			}
			break;
		    }
		}
		if (state == INRUN)
			putrun(runval, i - rstart, TRUE);	/* last bit */
		else
		    putdata(row + dstart, i - dstart);

		if (j < nrun-1)
		    SkipPixels(
			    the_hdr->priv.put.brun[j+1][0] - dend - 1,
			    FALSE, state == INRUN);
		else
		{
		    if (rowlen - dend > 0)
			SkipPixels(
			    rowlen - dend - 1,
			    TRUE, state == INRUN);
		}
	    }

	    if ( mask != the_hdr->ncolors - 1 )
		NewScanLine(FALSE);
	}
    }

    /* Increment to next scanline */
    the_hdr->priv.put.nblank++;

    /* flush every scanline */
    fflush( the_hdr->rle_file );
}

/*****************************************************************
 * TAG( rle_put_init )
 * 
 * Initialize the header structure for writing scanlines. 
 * Inputs:
 *	[None]
 * Outputs:
 * 	the_hdr:	Private portions initialized for output.
 * Assumptions:
 *	[None]
 * Algorithm:
 *	[None]
 */
void rle_put_init( the_hdr )
register rle_hdr *the_hdr;
{
    the_hdr->dispatch = RUN_DISPATCH;
    the_hdr->priv.put.nblank = 0;	/* Reinit static vars */
    /* Would like to be able to free previously allocated storage,
     * but can't count on a non-NULL value being a valid pointer.
     */
    the_hdr->priv.put.brun = NULL;
    the_hdr->priv.put.fileptr = 0;

    /* Only save alpha if alpha AND alpha channel bit are set. */
    if ( the_hdr->alpha )
	the_hdr->alpha = (RLE_BIT( *the_hdr, -1 ) != 0);
    else
	RLE_CLR_BIT( *the_hdr, -1 );
}

/*****************************************************************
 * TAG( rle_put_setup )
 * 
 * Initialize for writing RLE, and write header to output file.
 * Inputs:
 * 	the_hdr:	Describes output image.
 * Outputs:
 * 	the_hdr:	Initialized.
 * Assumptions:
 *	Lots of them.
 * Algorithm:
 *	[None]
 */
void rle_put_setup( the_hdr )
register rle_hdr * the_hdr;
{
    rle_put_init( the_hdr );
    Setup();
}

/*ARGSUSED*/
int DefaultBlockHook(the_hdr)
rle_hdr * the_hdr;
{
    					/* Do nothing */
}

/*****************************************************************
 * TAG( rle_puteof )
 * Write an EOF code into the output file.
 */
void rle_puteof( the_hdr )
register rle_hdr * the_hdr;
{
    /* Don't puteof twice. */
    if ( the_hdr->dispatch == NO_DISPATCH )
	return;
	PutEof();
    fflush( the_hdr->rle_file );
    /* Free storage allocated by rle_put_init. */
    if ( the_hdr->priv.put.brun != NULL )
    {
	free( the_hdr->priv.put.brun );
	the_hdr->priv.put.brun = NULL;
    }
    /* Signal that puteof has been called. */
    the_hdr->dispatch = NO_DISPATCH;
}

#ifndef FASTRUNS
/*****************************************************************
 * TAG( same_color )
 * 
 * Determine if the color at the given index position in the scan rows
 * is the same as the background color.
 * Inputs:
 * 	index:	    Index to the pixel position in each row.
 *	rows:	    array of pointers to the scanlines
 *	bg_color:   the background color
 *	ncolors:    number of color elements/pixel
 * Outputs:
 * 	TRUE if the color at row[*][i] is the same as bg_color[*].
 * Assumptions:
 *	[None]
 * Algorithm:
 *	[None]
 */
static int
same_color( index, rows, bg_color, ncolors, bits )
register rle_pixel *rows[];
register int bg_color[];
char *bits;
{
    register int i;

    for ( i = 0; i < ncolors; i++, bits++ )
	if ( *bits &&
	     rows[i][index] != bg_color[i] )
	    return 0;
    return 1;				/* all the same */
}
#endif /* !FASTRUNS */

/*****************************************************************
 * TAG( findruns )
 * 
 * Find runs not a given color in the row.
 * Inputs:
 * 	row:		Row of pixel values
 *	rowlen:		Number of pixels in the row.
 *	color:		Color to compare against.
 *	nrun:		Number of runs already found (in different colors).
 *	brun:		Runs found in other color channels already.
 * Outputs:
 * 	brun:		Modified to reflect merging of runs in this color.
 *	Returns number of runs in brun.
 * Assumptions:
 *
 * Algorithm:
 * 	Search for occurences of pixels not of the given color outside the
 *	runs already found.  When some are found, add a new run or extend
 *	an existing one.  Adjacent runs with fewer than two pixels intervening
 *	are merged.
 */
static int findruns( row, rowlen, color, nrun, brun )
register rle_pixel *row;
int rowlen, color, nrun;
short (*brun)[2];
{
    int i = 0, lower, upper;
    register int s, j;

#ifdef DEBUG
    fprintf( stderr, "findruns( " );
    for ( s = 0; s < rowlen; s++ )
	fprintf( stderr, "%2x.%s", row[s], (s % 20 == 19) ? "\n\t" : "" );
    if ( s % 20 != 0 )
	fprintf( stderr, "\n\t" );
    fprintf( stderr, "%d, %d, %d, \n\t", rowlen, color, nrun );
    for ( j = 0; j < nrun; j++ )
	fprintf( stderr, "(%3d,%3d) %s", brun[j][0], brun[j][1],
		(j % 6 == 5) ? "\n\t" : "" );
    fprintf( stderr, ")\n" );
#endif

    while ( i <= nrun )
    {
	/* Assert: 0 <= i <= rowlen
	 * brun[i] is the run following the "blank" space being
	 * searched.  If i == rowlen, search after brun[i-1].
	 */

	/* get lower and upper bounds of search */

	if ( i == 0 )
	    lower = 0;
	else
	    lower = brun[i-1][1] + 1;

	if ( i == nrun )
	    upper = rowlen - 1;
	else
	    upper = brun[i][0] - 1;

#ifdef DEBUG
	fprintf( stderr, "Searching before run %d from %d to %d\n",
		i, lower, upper );
#endif
	/* Search for beginning of run != color */
#if  defined(LOCC)&defined(vax)
	s = upper - skpc( (char *)row + lower, upper - lower + 1, color ) + 1;
#else
	for ( s = lower; s <= upper; s++ )
	    if ( row[s] != color )
		break;
#endif

	if ( s <= upper )	/* found a new run? */
	{
	    if ( s > lower + 1 || i == 0 ) /* disjoint from preceding run? */
	    {
#ifdef DEBUG
		fprintf( stderr, "Found new run starting at %d\n", s );
#endif
		/* Shift following runs up */
		for ( j = nrun; j > i; j-- )
		{
		    brun[j][0] = brun[j-1][0];
		    brun[j][1] = brun[j-1][1];
		}
		brun[i][0] = s;
		nrun++;
	    }
	    else
	    {
		i--;		/* just add to preceding run */
#ifdef DEBUG
		fprintf( stderr, "Adding to previous run\n" );
#endif
	    }

#if defined(LOCC)&defined(vax)
	    s = upper - locc( (char *)row + s, upper - s + 1, color ) + 1;
#else
	    for ( ; s <= upper; s++ )
		if ( row[s] == color )
		    break;
#endif
	    brun[i][1] = s - 1;

#ifdef DEBUG
	    fprintf( stderr, "Ends at %d", s - 1 );
#endif
	    if ( s >= upper && i < nrun - 1 ) /* merge with following run */
	    {
		brun[i][1] = brun[i+1][1];
		/* move following runs back down */
		for ( j = i + 2; j < nrun; j++ )
		{
		    brun[j-1][0] = brun[j][0];
		    brun[j-1][1] = brun[j][1];
		}
		nrun--;
#ifdef DEBUG
		fprintf( stderr, ", add to next run" );
#endif
	    }
#ifdef DEBUG
	    putc( '\n', stderr );
#endif
	}
	
	/* Search in next space */
	i++;
    }

    return nrun;
}

#ifdef LOCC
/*ARGSUSED*/
int locc( p, l, c )
register char *p;
register int l;
register int c;
{
    asm( "locc	r9,r10,(r11)" );
#ifdef lint
    c = (int) p;		/* why doesn't ARGSUSED work? */
    l = c;
    return l;			/* Needs return value, at least */
#endif
}

/*ARGSUSED*/
int skpc( p, l, c )
register char *p;
register int l;
register int c;
{
    asm( "skpc r9,r10,(r11)" );
#ifdef lint
    c = (int) p;		/* why doesn't ARGSUSED work? */
    l = c;
    return l;			/* Needs return value, at least */
#endif
}
#endif
/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is 
 * preserved on all copies.
 * 
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the 
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 *
 *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
 *  to have all "void" functions so declared.
 */
/* 
 * rle_global.c - Global variable initialization for rle routines.
 * 
 * Author:	Spencer W. Thomas
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	Thu Apr 25 1985
 * Copyright (c) 1985,1986 Spencer W. Thomas
 * 
 * $Id: rle_global.c,v 3.0 90/08/03 15:20:54 spencer Exp $
 */

extern int	RunSetup( ARB_ARGS ),
		RunSkipBlankLines( ARB_ARGS ),
		RunSetColor( ARB_ARGS ),
		RunSkipPixels( ARB_ARGS ),
		RunNewScanLine( ARB_ARGS ),
		Runputdata( ARB_ARGS ),
		Runputrun( ARB_ARGS ),
		RunputEof( ARB_ARGS );

extern void	NullputEof( ARB_ARGS );

struct rle_dispatch_tab rle_DTable[] = {
    {
	" OB",
	RunSetup,
	RunSkipBlankLines,
	RunSetColor,
	RunSkipPixels,
	RunNewScanLine,
	Runputdata,
	Runputrun,
	DefaultBlockHook,
	RunputEof
    },
};

static int bg_color[3] = { 0, 0, 0 };

rle_hdr rle_dflt_hdr = {
    RUN_DISPATCH,		/* dispatch value */
    3,				/* 3 colors */
    bg_color,			/* background color */
    0,				/* (alpha) if 1, save alpha channel */
    2,				/* (background) 0->just save pixels, */
				/* 1->overlay, 2->clear to bg first */
    0, 511,			/* (xmin, xmax) X bounds to save */
    0, 511,			/* (ymin, ymax) Y bounds to save */
    0,				/* ncmap (if != 0, save color map) */
    8,				/* cmaplen (log2 of length of color map) */
    NULL,			/* pointer to color map */
    NULL,			/* pointer to comment strings */
    stdout,			/* output file */
    { 7 }			/* RGB channels only */
    /* Can't initialize the union */
};
/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is 
 * preserved on all copies.
 * 
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the 
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 *
 *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
 *  to have all "void" functions so declared.
 */
/* 
 * Runput.c - General purpose Run Length Encoding.
 * 
 * Author:	Spencer W. Thomas
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	Mon Aug  9 1982
 * Copyright (c) 1982,1986 Spencer W. Thomas
 * 
 * $Id: Runput.c,v 3.0 90/08/03 15:19:58 spencer Exp $
 * 
 * Modified by:	Todd W. Fuqua
 * 	Date:	Jul 22 1984
 * convert to new RLE format to make room for larger frame buffers
 */

/* THIS IS WAY OUT OF DATE.  See rle.5.
 * The output file format is:
 * 
 * Word 0:	A "magic" number.  The top byte of the word contains
 *		the letter 'R' or the letter 'W'.  'W' indicates that
 *		only black and white information was saved.  The bottom
 *		byte is one of the following:
 *	' ':	Means a straight "box" save, -S flag was given.
 *	'B':	Image saved with background color, clear screen to
 *		background before restoring image.
 *	'O':	Image saved in overlay mode.
 * 
 * Words 1-6:	The structure
 * {     short   xpos,			Lower left corner
 *             ypos,
 *             xsize,			Size of saved box
 *             ysize;
 *     char    rgb[3];			Background color
 *     char    map;			flag for map presence
 * }
 * 
 * If the map flag is non-zero, then the color map will follow as 
 * 3*256 16 bit words, first the red map, then the green map, and
 * finally the blue map.
 * 
 * Following the setup information is the Run Length Encoded image.
 * Each instruction consists of a 4-bit opcode, a 12-bit datum and
 * possibly one or more following words (all words are 16 bits).  The
 * instruction opcodes are:
 * 
 * SkipLines (1):   The bottom 10 bits are an unsigned number to be added to
 *		    current Y position.
 * 
 * SetColor (2):    The datum indicates which color is to be loaded with
 * 		    the data described by the following ByteData and
 * 		    RunData instructions.  0->red, 1->green, 2->blue.  The
 * 		    operation also resets the X position to the initial
 * 		    X (i.e. a carriage return operation is performed).
 * 
 * SkipPixels (3):  The bottom 10 bits are an unsigned number to be
 * 		    added to the current X position.
 * 
 * ByteData (5):    The datum is one less than the number of bytes of
 * 		    color data following.  If the number of bytes is
 * 		    odd, a filler byte will be appended to the end of
 * 		    the byte string to make an integral number of 16-bit
 * 		    words.  The bytes are in PDP-11 order.  The X
 * 		    position is incremented to follow the last byte of
 * 		    data.
 * 
 * RunData (6):	    The datum is one less than the run length.  The
 * 		    following word contains (in its lower 8 bits) the
 * 		    color of the run.  The X position is incremented to
 * 		    follow the last byte in the run.
 */

#include	"stdio.h"
#include	"rle_code.h"
#ifdef USE_STDLIB_H
#include	<stdlib.h>
#include	<malloc.h>
#else

#ifdef USE_STRING_H
#include	<string.h>
#else
#include	<strings.h>
#endif /* USE_STRING_H */

#endif /* USE_STDLIB_H */

#define UPPER 255			/* anything bigger ain't a byte */

/*
 * Macros to make writing instructions with correct byte order easier.
 */
/* Write a two-byte value in little_endian order. */
#define	put16(a)    (putc((a)&0xff,rle_fd),putc(((a)>>8)&0xff,rle_fd))

/* short instructions */
#define mk_short_1(oper,a1)		/* one argument short */ \
    putc(oper,rle_fd), putc((char)a1,rle_fd)

#define mk_short_2(oper,a1,a2)		/* two argument short */ \
    putc(oper,rle_fd), putc((char)a1,rle_fd), put16(a2)

/* long instructions */
#define mk_long_1(oper,a1)		/* one argument long */ \
    putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), put16(a1)

#define mk_long_2(oper,a1,a2)		/* two argument long */ \
    putc((char)(LONG|oper),rle_fd), putc('\0', rle_fd), \
    put16(a1), put16(a2)

/* choose between long and short format instructions */
/* NOTE: these macros can only be used where a STATEMENT is legal */

#define mk_inst_1(oper,a1)		/* one argument inst */ \
    if (a1>UPPER) (mk_long_1(oper,a1)); else (mk_short_1(oper,a1))

#define mk_inst_2(oper,a1,a2)		/* two argument inst */ \
    if (a1>UPPER) (mk_long_2(oper,a1,a2)); else (mk_short_2(oper,a1,a2))

/* 
 * Opcode definitions
 */
#define	    RSkipLines(n)   	    mk_inst_1(RSkipLinesOp,(n))

#define	    RSetColor(c)	    mk_short_1(RSetColorOp,(c))
				    /* has side effect of performing */
				    /* "carriage return" action */

#define	    RSkipPixels(n)	    mk_inst_1(RSkipPixelsOp,(n))

#define	    RNewLine		    RSkipLines(1)

#define	    RByteData(n)	    mk_inst_1(RByteDataOp,n)
					/* followed by ((n+1)/2)*2 bytes */
					/* of data.  If n is odd, last */
					/* byte will be ignored */
					/* "cursor" is left at pixel */
					/* following last pixel written */

#define	    RRunData(n,c)	    mk_inst_2(RRunDataOp,(n),(c))
					/* next word contains color data */
					/* "cursor" is left at pixel after */
					/* end of run */

#define     REOF		    mk_inst_1(REOFOp,0)
					/* Really opcode only */

extern char *vax_pshort();

/*****************************************************************
 * TAG( RunSetup )
 * Put out initial setup data for RLE files.
 */
int RunSetup(the_hdr)
register rle_hdr * the_hdr;
{
    struct XtndRsetup setup;
    register FILE * rle_fd = the_hdr->rle_file;

    put16( RLE_MAGIC );

    if ( the_hdr->background == 2 )
	setup.h_flags = H_CLEARFIRST;
    else if ( the_hdr->background == 0 )
	setup.h_flags = H_NO_BACKGROUND;
    else
	setup.h_flags = 0;
    if ( the_hdr->alpha )
	setup.h_flags |= H_ALPHA;
    if ( the_hdr->comments != NULL && *the_hdr->comments != NULL )
	setup.h_flags |= H_COMMENT;

    setup.h_ncolors = the_hdr->ncolors;
    setup.h_pixelbits = 8;		/* Grinnell dependent */
    if ( the_hdr->ncmap > 0 && the_hdr->cmap == NULL )
    {
	fprintf( stderr,
		 "Color map of size %d*%d specified, but not supplied\n" );
	the_hdr->ncmap = 0;
    }
    setup.h_cmaplen = the_hdr->cmaplen;	/* log2 of color map size */
    setup.h_ncmap = the_hdr->ncmap;	/* no of color channels */
    vax_pshort(setup.hc_xpos,the_hdr->xmin);
    vax_pshort(setup.hc_ypos,the_hdr->ymin);
    vax_pshort(setup.hc_xlen,the_hdr->xmax - the_hdr->xmin + 1);
    vax_pshort(setup.hc_ylen,the_hdr->ymax - the_hdr->ymin + 1);
    fwrite((char *)&setup, SETUPSIZE, 1, rle_fd);
    if ( the_hdr->background != 0 )
    {
	register int i;
	register rle_pixel *background =
	    (rle_pixel *)malloc( (unsigned)(the_hdr->ncolors + 1) );
	register int *bg_color;
	/* 
	 * If even number of bg color bytes, put out one more to get to 
	 * 16 bit boundary.
	 */
	bg_color = the_hdr->bg_color;
	for ( i = 0; i < the_hdr->ncolors; i++ )
	    background[i] =  *bg_color++;
	/* Extra byte, if written, should be 0. */
	background[i] = 0;
	fwrite((char *)background, (the_hdr->ncolors / 2) * 2 + 1, 1, rle_fd);
	free( background );
    }
    else
	putc( '\0', rle_fd );
    if (the_hdr->ncmap > 0)
    {
	/* Big-endian machines are harder */
	register int i, nmap = (1 << the_hdr->cmaplen) *
			       the_hdr->ncmap;
	register char *h_cmap = (char *)malloc( nmap * 2 );
	if ( h_cmap == NULL )
	{
	    fprintf( stderr, "Malloc failed for color map of size %d\n",
		     nmap );
	    exit( 1 );
	}
	for ( i = 0; i < nmap; i++ )
	    vax_pshort( &h_cmap[i*2], the_hdr->cmap[i] );

	fwrite( h_cmap, nmap, 2, rle_fd );
	free( h_cmap );
    }

    /* Now write out comments if given */
    if ( setup.h_flags & H_COMMENT )
    {
	int comlen;
	register CONST_DECL char ** com_p;

	/* Get the total length of comments */
	comlen = 0;
	for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
	    comlen += 1 + strlen( *com_p );

	put16( comlen );
	for ( com_p = the_hdr->comments; *com_p != NULL; com_p++ )
	    fwrite( *com_p, 1, strlen( *com_p ) + 1, rle_fd );

	if ( comlen & 1 )	/* if odd length, round up */
	    putc( '\0', rle_fd );
    }
}

/*****************************************************************
 * TAG( RunSkipBlankLines )
 * Skip one or more blank lines in the RLE file.
 */
int RunSkipBlankLines(nblank, the_hdr)
int nblank;
register rle_hdr * the_hdr;
{
    register FILE * rle_fd = the_hdr->rle_file;
    RSkipLines(nblank);
}

/*****************************************************************
 * TAG( RunSetColor )
 * Select a color and do carriage return.
 * color: 0 = Red, 1 = Green, 2 = Blue.
 */
int RunSetColor(c, the_hdr)
int c;
register rle_hdr * the_hdr;
{
    register FILE * rle_fd = the_hdr->rle_file;
    RSetColor(c);
}

/*****************************************************************
 * TAG( RunSkipPixels )
 * Skip a run of background.
 */

/* ARGSUSED */
int RunSkipPixels(nskip, last, wasrun, the_hdr)
int nskip, last, wasrun;
register rle_hdr * the_hdr;
{
    register FILE * rle_fd = the_hdr->rle_file;
    if (! last && nskip > 0)
    {
	RSkipPixels(nskip);
    }
}

/*****************************************************************
 * TAG( RunNewScanLine )
 * Perform a newline action.  Since CR is implied by the Set Color
 * operation, only generate code if the newline flag is true.
 */
int RunNewScanLine (int flag, register rle_hdr *the_hdr)
/*
int RunNewScanLine(flag, the_hdr)
int flag;
register rle_hdr * the_hdr;
*/
{
    register FILE * rle_fd = the_hdr->rle_file;
    if (flag)
    {
	RNewLine;
    }
}

/*****************************************************************
 * TAG( Runputdata )
 * Put one or more pixels of byte data into the output file.
 */
int Runputdata(buf, n, the_hdr)
rle_pixel * buf;
int n;
register rle_hdr * the_hdr;
{
    register FILE * rle_fd = the_hdr->rle_file;
    if (n == 0)
	return;

    RByteData(n-1);
    fwrite((char *)buf, n, 1, rle_fd);
    if ( n & 1 )
	putc( 0, rle_fd );
}

/*****************************************************************
 * TAG( Runputrun )
 * Output a single color run.
 */

/* ARGSUSED */
int Runputrun(color, n, last, the_hdr)
int color, n, last;
register rle_hdr * the_hdr;
{
    register FILE * rle_fd = the_hdr->rle_file;
    RRunData(n-1,color);
}


/*****************************************************************
 * TAG( RunputEof )
 * Output an EOF opcode
 */
int RunputEof( the_hdr )
register rle_hdr * the_hdr;
{
    register FILE * rle_fd = the_hdr->rle_file;
    REOF;
}
/*
 *			V A X S H O R T
 *
 *  Code to manipulate 16-bit integers in VAX order in a
 *  machine independent manner.
 *
 *  (VAX is a trademark of Digital Equipment Corporation)
 *
 *  Author -
 *	Michael John Muuss
 *  
 *  Source -
 *	SECAD/VLD Computing Consortium, Bldg 394
 *	The U. S. Army Ballistic Research Laboratory
 *	Aberdeen Proving Ground, Maryland  21005-5066
 *  
 *  Distribution Status -
 *	Public Domain, Distribution Unlimitied.
 */
#ifndef lint
static char RCSid[] = "@(#)$Id: vaxshort.c,v 3.0 90/08/03 15:21:30 spencer Exp $ (BRL)";
#endif

/*
 *			V A X _ P S H O R T
 */
char *vax_pshort(msgp, s)
register char *msgp;
register unsigned short s;
{

	msgp[0] = s & 0xFF;
	msgp[1] = s >> 8;
	return(msgp+2);
}
