/* bmp2gif.c -- See end-of-file for (C) */
/* This was written for Microsoft 32-bit-integer compilers--it
 * should compile with
 *	cl gif2bmp.c
 * to produce the executable gif2bmp.exe
 *
 * The Microsoft oddities are:
 *   The funny include files -- they may be omitted on compilers
 *   that can not find them (stdio.h better be there, however)
 * #pragma pack(1) -- This forces the BITMAPFILEHEADER structure
 *   to be the same length in memory as in files (otherwise, the structure
 *   is padded out to be a multiple of 8? bytes long
 * Note that Microsoft uses all-caps for typedefs.  Ugh.
 */
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>

typedef unsigned char byte;
typedef unsigned short WORD;
typedef unsigned long DWORD;

#pragma pack(1)
typedef struct tagRGBQUAD {
	byte	rgbBlue;
	byte	rgbGreen;
	byte	rgbRed;
	byte	rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPFILEHEADER {
	WORD	bfType;
	DWORD	bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
	DWORD	bfOffBits;
} BITMAPFILEHEADER;
typedef BITMAPFILEHEADER *PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
  	DWORD	   biSize;
  	DWORD	   biWidth;
  	DWORD	   biHeight;
  	WORD	   biPlanes;
  	WORD	   biBitCount;

	DWORD	   biCompression;
	DWORD	   biSizeImage;
	DWORD	   biXPelsPerMeter;
	DWORD	   biYPelsPerMeter;
	DWORD	   biClrUsed;
	DWORD	   biClrImportant;
} BITMAPINFOHEADER;

BITMAPFILEHEADER hdr;
BITMAPINFOHEADER bi;
long wib;
int yat;
unsigned char cmap[256*4];	/* Bytes of blue, green, red, reserved */
unsigned char omap[256*4];	/* Output colormap */
unsigned char *scanline;
unsigned char used[256];

FILE *fpin;	/* Input file fp */
int c666= 0;	/* Force output colormap to 666 colors */
int ncolors;

int fread_chk(char *cp, int n, int count, FILE *fp){
	int c= fread(cp, n, count, fp);
	if(c!=count){
		perror("Read error:");
		exit(1);
	}
}
int fwrite_chk(char *cp, int n, int count, FILE *fp){
	int c= fwrite(cp, n, count, fp);
	if(c!=count){
		perror("Write error:");
		exit(1);
	}
}
static int dib_wib(int bitcount, int wi){
	switch (bitcount){
	case 1: wi= (wi+31) >> 3; break;
	case 4:	wi= (wi+7)  >> 1; break;
	case 8:	wi=  wi+3; break;
        case 24:wi= (wi*3)+3; break;
	}
	return wi & ~3;
}
void err(char *msg){
	fprintf(stderr, "%s\n", msg);
	exit(5);
}
void gulp(char *dibname){
	int nbytes;
	int v, y;

	if((fpin= fopen (dibname, "rb"))==0){
		perror(dibname);
		exit(0);
	}
	fread_chk((char *)(&hdr),1,sizeof(hdr),fpin);
	if(hdr.bfType!= 0x4d42)
		err("Image not a .bmp");

	fread_chk((char *)(&bi), 1, sizeof(bi), fpin);

	wib= dib_wib((int)bi.biBitCount, (int)bi.biWidth);
	bi.biSizeImage= bi.biHeight * wib;
	if(bi.biBitCount != 8)
		err("Only 8-bit .bmp images are permitted");
	if(bi.biBitCount<=8){
		v= (int)((hdr.bfOffBits - bi.biSize - sizeof(BITMAPFILEHEADER))/sizeof(RGBQUAD));
		bi.biClrUsed= v;
		if(v>0)
			fread_chk(cmap, sizeof(RGBQUAD), v, fpin);
		if(c666){
			int k= 4*v;
			while(--k>=0)
				cmap[k]= 51*((cmap[k]+25)/51);
		}
	}
	scanline= malloc((int)wib);
	if(scanline==0)
		err("Not enough room for the scanline");
	fread_chk(scanline, 1, (int)wib, fpin);
	yat= 0;	
}
static int GetPixel(int x, int y){
	y= (int)(bi.biHeight-1-y);	/* bmp files are upside-down */
	if(y!=yat){
		if(y!=yat+1)
			if(0!=fseek(fpin, (y-(yat+1))*wib, SEEK_CUR)){
				perror("Seek on input file");
				exit(1);
			}
		fread_chk(scanline, 1, (int)wib, fpin);
		yat= y;
	}
	return used[scanline[x]];
}
int formoutputcmap(){
	int ncolors= 0;
	int x, y;
	for(x= 0; x<256; x++)used[x]= 0;
	for(y= 0; y<(int)bi.biHeight; y++){
		if(y!=0)
			fread_chk(scanline, 1, (int)wib, fpin);
		for(x= 0; x<(int)bi.biWidth; x++)
			used[scanline[x]]= 1;
	}
	/* Count the number of colors used */
	for(x= 0; x<256; x++)ncolors += used[x];
	if(ncolors<2)
		ncolors= 2;
	for(x= y= 0; x<256; x++)if(used[x]!=0){
		used[x]= y/3;
		omap[y++]= cmap[4*x+2];
		omap[y++]= cmap[4*x+1];
		omap[y++]= cmap[4*x];
	}
	fclose(fpin);
	return ncolors;
}
int nearestcolor(int *rgb){
	int k;
	int pv= 0;
	int n= 1 << ((int)bi.biBitCount);
	long del[3], len, minlen= 3*256L*256L;
	unsigned char *cp= cmap;

	for(k= 0; k<n; k++, cp+= 4){
		del[0]= cp[0]-rgb[2];
		del[1]= cp[1]-rgb[1];
		del[2]= cp[2]-rgb[0];
		len= del[0]*del[0] + del[1]*del[1] + del[2]*del[2];
		if(len<minlen){
			minlen= len;
			pv= k;
		}
	}
	return pv;
}
char *note[]= {
	"Usage: [-i] [-x # [# #]] [-b # [# #]] source.bmp dest.gif",
	"Create a .gif file from a Windows .bmp file",
	"Options:",
	"-i    Interlace [default not]",
	"-x #  Set pvalue # transparent (# # # for transparent rgb)",
	"-b #  Set pvalue # background [default 0]",
//	"-p #  Bits per pixel (override the number in the .bmp file)",
	"-c X  Add comment X (use quoted string argument)",
	"-n    Convert colors to nearest Netscape color [multiple of 51]",
	0};
char *comment;
typedef int (* ifunptr)(int, int);
static void GIFEncode(FILE *fp, int GWidth, int GHeight,
	int GInterlace, int Background, int Transparent,
	int BitsPerPixel, unsigned char *cmap, ifunptr GetPixel );
void main(int ac, char **av){
	int k;
	int GWidth;
	int GHeight;
	FILE *fp;
	int GInterlace= 0;
	int Background;
	int Transparent;
	int BitsPerPixel= -1;

	char *cp;
	static int xpar[3]= {-1,-1,-1};
	static int bg[3]= {0,-1,-1};
	char *srcname= 0;
	char *dstname= 0;

	while(cp= *++av)if(*cp++=='-')switch(*cp++){
	case 'n':	c666= 1; break;
	case 'c':	comment= *++av; break;
//	case 'p':	BitsPerPixel= atoi(*++av);
//			if(BitsPerPixel>8)
//				BitsPerPixel= 8;
//			break;
	case 'i':	GInterlace= 1; break;
	case 'x':	xpar[0]= atoi(*++av);
			if(av[1][0]>='0' && av[1][0]<='9'){
				xpar[1]= atoi(*++av);
				xpar[2]= atoi(*++av);
			} break;
	case 'b':	bg[0]= atoi(*++av);
			if(av[1][0]>='0' && av[1][0]<='9'){
				bg[1]= atoi(*++av);
				bg[2]= atoi(*++av);
			} break;
	default:
	erra:		for(av= note; *av; ++av)
				fprintf(stderr, "%s\n", *av);
			exit(1);
	}else if(srcname==0)
		srcname= *av;
	else if(dstname==0)
		dstname= *av;
	else
		goto erra;
	if(dstname==0)
		goto erra;

	/* Open the source bmp */
	gulp(srcname);

	/* Choose the output colors */
	ncolors= formoutputcmap();
	for(BitsPerPixel= 0; (1 << BitsPerPixel)<ncolors; BitsPerPixel++);
	gulp(srcname);

	/* Create the gif file */
	fp= fopen(dstname, "wb");
	if(fp==0){
		perror(dstname);
		exit(1);
	}
	/* Transfer some parameters */
	GWidth= (int)bi.biWidth;
	GHeight= (int)bi.biHeight;
	Transparent= xpar[0];
	if(xpar[1]>=0)
		Transparent= used[nearestcolor(xpar)];
	Background= bg[0];
	if(bg[1]>=0)
		Background= used[nearestcolor(bg)];

	GIFEncode(fp, GWidth, GHeight,
		GInterlace, Background, Transparent,
		BitsPerPixel, omap, GetPixel);

	printf("%d colors in %s\n", ncolors, srcname);
}
/*****************************************************************************
 *
 * GIFENCODE.C	  - GIF Image compression interface
 *
 * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
 *	      BitsPerPixel, Red, Green, Blue, GetPixel )
 *
 *****************************************************************************/
#define TRUE 1
#define FALSE 0

static int Width, Height;
static int curx, cury;
static long CountDown;
static int Pass = 0;
static int Interlace;
typedef int code_int;

#ifdef SIGNED_COMPARE_SLOW
typedef unsigned long int count_int;
typedef unsigned short int count_short;
#else /*SIGNED_COMPARE_SLOW*/
typedef long int          count_int;
#endif /*SIGNED_COMPARE_SLOW*/

static void Putword ( int w, FILE* fp );
static void compress ( int init_bits, FILE* outfile, ifunptr ReadValue );
static void output ( code_int code );
static void cl_block ( void );
static void cl_hash ( count_int hsize );
static void writeerr ( void );
static void char_init ( void );
static void char_out ( int c );
static void flush_char ( void );


/*
 * Bump the 'curx' and 'cury' to point to the next pixel
 */
static void BumpPixel() {
	/* Bump the current X position */
	++curx;

	/*
	 * If we are at the end of a scan line, set curx back to the beginning
	 * If we are interlaced, bump the cury to the appropriate spot,
	 * otherwise, just increment it.
	 */
	if( curx == Width ) {
		curx = 0;
		if( !Interlace )
			++cury;
		else {
		     switch( Pass ) {
		       case 0:
			  cury += 8;
			  if( cury >= Height ) {
				++Pass;
				cury = 4;
			  } break;
		       case 1:
			  cury += 8;
			  if( cury >= Height ) {
				++Pass;
				cury = 2;
			  } break;
		       case 2:
			  cury += 4;
			  if( cury >= Height ) {
			     ++Pass;
			     cury = 1;
			  } break;
		       case 3:
			  cury += 2;
			  break;
			}
		}
	}
}

/*
 * Return the next pixel from the image
 */
static int GIFNextPixel(ifunptr getpixel){
	int r;

	if( CountDown == 0 )
		return EOF;
	--CountDown;

	r = ( * getpixel )( curx, cury );
	BumpPixel();
	return r;
}

/* public */
static void GIFEncode(FILE *fp, int GWidth, int GHeight,
	int GInterlace, int Background, int Transparent,
	int BitsPerPixel, unsigned char *omap, ifunptr GetPixel ){

	int B;
	int RWidth, RHeight;
	int LeftOfs, TopOfs;
	int Resolution;
	int ColorMapSize;
	int InitCodeSize;
	int i;

	Interlace = GInterlace;

	ColorMapSize = 1 << BitsPerPixel;

	RWidth = Width = GWidth;
	RHeight = Height = GHeight;
	LeftOfs = TopOfs = 0;

	Resolution = BitsPerPixel;

	/* Calculate number of bits we are expecting */
	CountDown = (long)Width * (long)Height;

	/* Indicate which pass we are on (if interlace) */
	Pass = 0;

	/* The initial code size */
	if( BitsPerPixel <= 1 )
		InitCodeSize = 2;
	else
		InitCodeSize = BitsPerPixel;

	/* Set up the current x and y position */
	curx = cury = 0;

	/* Write the Magic header */
	fwrite_chk( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );

	/* Write out the screen width and height */
	Putword( RWidth, fp );
	Putword( RHeight, fp );

	/* Indicate that there is a global colour map */
	B = 0x80;	/* Yes, there is a color map */

	/* OR in the resolution */
	B |= (Resolution - 1) << 5;

	/* OR in the Bits per Pixel */
	B |= (BitsPerPixel - 1);

	/* Write it out */
	fputc( B, fp );

	/* Write out the Background colour */
	fputc( Background, fp );

	/* Byte of 0's (future expansion) */
	fputc( 0, fp );

	/* Write out the Global Colour Map */
	for( i=0; i<ColorMapSize; ++i ) {
		fputc( omap[0], fp );	// Red
		fputc( omap[1], fp );	// Green
		fputc( omap[2], fp );	// Blue
		omap += 3;
	}
	/* Write out extension for transparent colour index, if necessary. */
	if ( Transparent >= 0 ) {
		fputc( '!', fp );
		fputc( 0xf9, fp );
		fputc( 4, fp );
		fputc( 1, fp );
		fputc( 0, fp );
		fputc( 0, fp );
		fputc( Transparent, fp );
		fputc( 0, fp );
	}
	if (comment!=0 && *comment){
		fputc( '!', fp);
		fputc( 0xfe, fp);
		fputc( strlen(comment), fp);
		do
			fputc( *comment, fp);
		while(*comment++);
	}
	/* Write an Image separator */
	fputc( ',', fp );

	/* Write the Image header */
	Putword( LeftOfs, fp );
	Putword( TopOfs, fp );
	Putword( Width, fp );
	Putword( Height, fp );

	/* Write out whether or not the image is interlaced */
	if( Interlace )
		fputc( 0x40, fp );
	else
		fputc( 0x00, fp );

	/* Write out the initial code size */
	if(EOF==fputc( InitCodeSize, fp )){
		perror("Writing output");
		exit(1);
	}
	/* Go and actually compress the data */
	compress( InitCodeSize+1, fp, GetPixel );

	/* Write out a Zero-length packet (to end the series) */
	fputc( 0, fp );

	/* Write the GIF file terminator */
	fputc( ';', fp );

	/* And close the file */
	fclose( fp );
}

/* Write out a word to the GIF file */
static void Putword(int w, FILE *fp ){
	fputc( w & 0xff, fp );
	fputc( (w / 256) & 0xff, fp );
}
/***************************************************************************
 *
 *  GIFCOMPR.C	     - GIF Image compression routines
 *
 *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
 *  David Rowley (mgardi@watdcsu.waterloo.edu)
 *
 ***************************************************************************/

/* General DEFINEs  */

#define BITS	12
#define HSIZE  5003	       /* 80% occupancy */

#ifdef NO_UCHAR
 typedef char	char_type;
#else /*NO_UCHAR*/
 typedef	unsigned char	char_type;
#endif /*NO_UCHAR*/

/*
 *
 * GIF Image compression - modified 'compress'
 *
 * Based on: compress.c - File compression ala IEEE Computer, June 1984.
 *
 * By Authors:	Spencer W. Thomas	(decvax!harpo!utah-cs!utah-gr!thomas)
 *		Jim McKie		(decvax!mcvax!jim)
 *		Steve Davies		(decvax!vax135!petsd!peora!srd)
 *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
 *		James A. Woods		(decvax!ihnp4!ames!jaw)
 *		Joe Orost		(decvax!vax135!petsd!joe)
 *
 */
#include <ctype.h>

#define ARGVAL() (*++(*argv) || (--argc && *++argv))

static int n_bits;			  /* number of bits/code */
static int maxbits = BITS;		  /* user settable max # bits/code */
static code_int maxcode;		  /* maximum code, given n_bits */
static code_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this code */
#ifdef COMPATIBLE		/* But wrong! */
# define MAXCODE(n_bits)	((code_int) 1 << (n_bits) - 1)
#else /*COMPATIBLE*/
# define MAXCODE(n_bits)	(((code_int) 1 << (n_bits)) - 1)
#endif /*COMPATIBLE*/

static count_int htab [HSIZE];
static unsigned short codetab [HSIZE];
#define HashTabOf(i)	   htab[i]
#define CodeTabOf(i)	codetab[i]

static code_int hsize = HSIZE;		       /* for dynamic table sizing */

/*
 * To save much memory, we overlay the table used by compress() with those
 * used by decompress().  The tab_prefix table is the same size and type
 * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
 * get this from the beginning of htab.  The output stack uses the rest
 * of htab, and contains characters.  There is plenty of room for any
 * possible stack (stack used to be 8000 characters).
 */

#define tab_prefixof(i) CodeTabOf(i)
#define tab_suffixof(i)        ((char_type*)(htab))[i]
#define de_stack	       ((char_type*)&tab_suffixof((code_int)1<<BITS))

static code_int free_ent = 0;		       /* first unused entry */

/*
 * block compression parameters -- after all codes are used up,
 * and compression rate changes, start over.
 */
static int clear_flg = 0;

static int offset;
static long int in_count = 1;		 /* length of input */
static long int out_count = 0;		 /* # of codes output (for debugging) */

/*
 * compress stdin to stdout
 *
 * Algorithm:  use open addressing double hashing (no chaining) on the
 * prefix code / next character combination.  We do a variant of Knuth's
 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
 * secondary probe.  Here, the modular division first probe is gives way
 * to a faster exclusive-or manipulation.  Also do block compression with
 * an adaptive reset, whereby the code table is cleared when the compression
 * ratio decreases, but after the table fills.	The variable-length output
 * codes are re-sized at this point, and a special CLEAR code is generated
 * for the decompressor.  Late addition:  construct the table according to
 * file size for noticeable speed improvement on small files.  Please direct
 * questions about this implementation to ames!jaw.
 */

static int g_init_bits;
static FILE* g_outfile;

static int ClearCode;
static int EOFCode;

static void compress(int init_bits, FILE *outfile, ifunptr ReadValue ){
    register long fcode;
    register code_int i /* = 0 */;
    register int c;
    register code_int ent;
    register code_int disp;
    register code_int hsize_reg;
    register int hshift;

    /*
     * Set up the globals:  g_init_bits - initial number of bits
     *			    g_outfile	- pointer to output file
     */
    g_init_bits = init_bits;
    g_outfile = outfile;

    /*
     * Set up the necessary values
     */
    offset = 0;
    out_count = 0;
    clear_flg = 0;
    in_count = 1;
    maxcode = MAXCODE(n_bits = g_init_bits);

    ClearCode = (1 << (init_bits - 1));
    EOFCode = ClearCode + 1;
    free_ent = ClearCode + 2;

    char_init();

    ent = GIFNextPixel( ReadValue );

    hshift = 0;
    for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
	++hshift;
    hshift = 8 - hshift;		/* set hash code range bound */

    hsize_reg = hsize;
    cl_hash( (count_int) hsize_reg);		/* clear hash table */

    output( (code_int)ClearCode );

#ifdef SIGNED_COMPARE_SLOW
    while ( (c = GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
#else /*SIGNED_COMPARE_SLOW*/
    while ( (c = GIFNextPixel( ReadValue )) != EOF ) {	/* } */
#endif /*SIGNED_COMPARE_SLOW*/

	++in_count;

	fcode = (long) (((long) c << maxbits) + ent);
	i = (((code_int)c << hshift) ^ ent);	/* xor hashing */

	if ( HashTabOf (i) == fcode ) {
	    ent = CodeTabOf (i);
	    continue;
	} else if ( (long)HashTabOf (i) < 0 )	   /* empty slot */
	    goto nomatch;
	disp = hsize_reg - i;		/* secondary hash (after G. Knott) */
	if ( i == 0 )
	    disp = 1;
probe:
	if ( (i -= disp) < 0 )
	    i += hsize_reg;

	if ( HashTabOf (i) == fcode ) {
	    ent = CodeTabOf (i);
	    continue;
	}
	if ( (long)HashTabOf (i) > 0 )
	    goto probe;
nomatch:
	output ( (code_int) ent );
	++out_count;
	ent = c;
#ifdef SIGNED_COMPARE_SLOW
	if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
#else /*SIGNED_COMPARE_SLOW*/
	if ( free_ent < maxmaxcode ) {	/* } */
#endif /*SIGNED_COMPARE_SLOW*/
	    CodeTabOf (i) = free_ent++; /* code -> hashtable */
	    HashTabOf (i) = fcode;
	} else
		cl_block();
    }
    /*
     * Put out the final code.
     */
    output( (code_int)ent );
    ++out_count;
    output( (code_int) EOFCode );
}

/*****************************************************************
 * TAG( output )
 *
 * Output the given code.
 * Inputs:
 *	code:	A n_bits-bit integer.  If == -1, then EOF.  This assumes
 *		that n_bits =< (long)wordsize - 1.
 * Outputs:
 *	Outputs code to the file.
 * Assumptions:
 *	Chars are 8 bits long.
 * Algorithm:
 *	Maintain a BITS character long buffer (so that 8 codes will
 * fit in it exactly).	Use the VAX insv instruction to insert each
 * code in turn.  When the buffer fills up empty it and start over.
 */

static unsigned long cur_accum = 0;
static int cur_bits = 0;

static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
				  0x001F, 0x003F, 0x007F, 0x00FF,
				  0x01FF, 0x03FF, 0x07FF, 0x0FFF,
				  0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };

static void
output( code )
code_int  code;
{
    cur_accum &= masks[ cur_bits ];

    if( cur_bits > 0 )
	cur_accum |= ((long)code << cur_bits);
    else
	cur_accum = code;

    cur_bits += n_bits;

    while( cur_bits >= 8 ) {
	char_out( (unsigned int)(cur_accum & 0xff) );
	cur_accum >>= 8;
	cur_bits -= 8;
    }

    /*
     * If the next entry is going to be too big for the code size,
     * then increase it, if possible.
     */
   if ( free_ent > maxcode || clear_flg ) {

	    if( clear_flg ) {

		maxcode = MAXCODE (n_bits = g_init_bits);
		clear_flg = 0;

	    } else {

		++n_bits;
		if ( n_bits == maxbits )
		    maxcode = maxmaxcode;
		else
		    maxcode = MAXCODE(n_bits);
	    }
	}

    if( code == EOFCode ) {
	/*
	 * At EOF, write the rest of the buffer.
	 */
	while( cur_bits > 0 ) {
		char_out( (unsigned int)(cur_accum & 0xff) );
		cur_accum >>= 8;
		cur_bits -= 8;
	}

	flush_char();

	fflush( g_outfile );

	if( ferror( g_outfile ) )
		writeerr();
    }
}

/*
 * Clear out the hash table
 */
static void
cl_block ()		/* table clear for block compress */
{

	cl_hash ( (count_int) hsize );
	free_ent = ClearCode + 2;
	clear_flg = 1;

	output( (code_int)ClearCode );
}

static void
cl_hash(hsize)		/* reset code table */
register count_int hsize;
{

	register count_int *htab_p = htab+hsize;

	register long i;
	register long m1 = -1;

	i = hsize - 16;
	do {				/* might use Sys V memset(3) here */
		*(htab_p-16) = m1;
		*(htab_p-15) = m1;
		*(htab_p-14) = m1;
		*(htab_p-13) = m1;
		*(htab_p-12) = m1;
		*(htab_p-11) = m1;
		*(htab_p-10) = m1;
		*(htab_p-9) = m1;
		*(htab_p-8) = m1;
		*(htab_p-7) = m1;
		*(htab_p-6) = m1;
		*(htab_p-5) = m1;
		*(htab_p-4) = m1;
		*(htab_p-3) = m1;
		*(htab_p-2) = m1;
		*(htab_p-1) = m1;
		htab_p -= 16;
	} while ((i -= 16) >= 0);

	for ( i += 16; i > 0; --i )
		*--htab_p = m1;
}

static void
writeerr()
{
	err( "error writing output file" );
}

/******************************************************************************
 *
 * GIF Specific routines
 *
 ******************************************************************************/

/*
 * Number of characters so far in this 'packet'
 */
static int a_count;

/*
 * Set up the 'byte output' routine
 */
static void char_init(){
	a_count = 0;
}

/*
 * Define the storage for the packet accumulator
 */
static char accum[ 256 ];

/*
 * Add a character to the end of the current packet, and if it is 254
 * characters, flush the packet to disk.
 */
static void
char_out( int c ){
	accum[ a_count++ ] = c;
	if( a_count >= 254 )
		flush_char();
}
/*
 * Flush the packet to disk, and reset the accumulator
 */
static void flush_char(){
	if( a_count > 0 ) {
		fputc( a_count, g_outfile );
		fwrite_chk( accum, 1, a_count, g_outfile );
		a_count = 0;
	}
}
/*
**
** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
** Lempel-Zim compression based on "compress".
**
** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
**
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** The Graphics Interchange Format(c) is the Copyright property of
** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
** CompuServe Incorporated.
*/
/*****************************************************************************\
*               Windows functions, types, and definitions                     *
*               Version 3.10                                                  *
*               Copyright (c) 1985-1992, Microsoft Corp. All rights reserved. *
*******************************************************************************
*
*(C)1996 Ephraim Cohen--subject to the above,
** permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notices appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
**
*/

