/* Copyright (C) 1992 by Gustaf Neumann, Stefan Nusser

 *      Wirtschaftsuniversitaet Wien, 
 *      Abteilung fuer Wirtschaftsinformatik
 *      Augasse 2-6, 
 *      A-1090 Vienna, Austria
 *      neumann@wu-wien.ac.at, nusser@wu-wien.ac.at

 * 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 notice appears in all copies and that both that
 * copyright notice and this permission notice appear in all supporting
 * documentation.  This software is provided "as is" without expressed or
 * implied warranty.

 * Creation: Sun Jan 23 01:42:10 EST 1994 on syllog2.watson.ibm.com
 * Author: genc
 * Version: 0.95999999999999996

 */
#ifdef HTML

#define HTML_C

#include "wafe.h"
#include<errno.h>
#include <HTML.h>
#define hTMLWidgetClass htmlWidgetClass

/* 
 * ******* begin required file <gifread.inc> *******
 */
/* make emcas happy -*-C-*-  make emacs happy */

/* +-------------------------------------------------------------------+ */
/* | Copyright 1990, David Koblas.                                     | */
/* |   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 notice 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.           | */
/* +-------------------------------------------------------------------+ */


#define	MAXCOLORMAPSIZE		256

#define	TRUE	1
#define	FALSE	0

#define CM_RED		0
#define CM_GREEN	1
#define CM_BLUE		2

#define	MAX_LWZ_BITS		12

#define INTERLACE		0x40
#define LOCALCOLORMAP	0x80
#define BitSet(byte, bit)	(((byte) & (bit)) == (bit))

#define	ReadOK(file,buffer,len)	(fread(buffer, len, 1, file) != 0)

#define LM_to_uint(a,b)			(((b)<<8)|(a))

struct {
	unsigned int	Width;
	unsigned int	Height;
	unsigned char	ColorMap[3][MAXCOLORMAPSIZE];
	unsigned int	BitPixel;
	unsigned int	ColorResolution;
	unsigned int	Background;
	unsigned int	AspectRatio;
} GifScreen;

struct {
	int	transparent;
	int	delayTime;
	int	inputFlag;
	int	disposal;
} Gif89 = { -1, -1, -1, 0 };

int	verbose;
int	showComment;


/*
unsigned char *ReadGIF ARGS(( FILE	*fd, int imageNumber ));
static int ReadColorMap ARGS(( FILE *fd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE] ));
static int DoExtension ARGS(( FILE *fd, int label ));
static int GetDataBlock ARGS(( FILE *fd, unsigned char  *buf ));
static int GetCode ARGS(( FILE *fd, int code_size, int flag ));
static int LWZReadByte ARGS(( FILE *fd, int flag, int input_code_size ));
static unsigned char *ReadImage ARGS(( FILE *fd, int len, int height, unsigned char cmap[3][MAXCOLORMAPSIZE], int interlace, int ignore ));
*/

static int ReadColorMap();
static int DoExtension();
static int GetDataBlock();
static int GetCode();
static int LWZReadByte();
static unsigned char *ReadImage();

unsigned char *
ReadGIF(fd, w, h, colrs)
FILE	*fd;
int *w, *h;
XColor *colrs;
{
	unsigned char	buf[16];
	unsigned char	*data;
	unsigned char	c;
	unsigned char	localColorMap[3][MAXCOLORMAPSIZE];
	int		useGlobalColormap;
	int		bitPixel;
	int		imageCount = 0;
	char		version[4];
	int		imageNumber = 1;
	int		i;

	verbose = FALSE;
	showComment = FALSE;

	if (! ReadOK(fd,buf,6))
	{
#if 0
		fprintf(stderr, "error reading magic number\n");
#endif
		return(NULL);
	}

	if (strncmp(buf,"GIF",3) != 0)
	{
#if 0
		if (verbose)
			fprintf(stderr, "not a GIF file\n");
#endif
		return(NULL);
	}

	strncpy(version, (char *)(buf + 3), 3);
	version[3] = '\0';

	if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0))
	{
#if 0
		fprintf(stderr, "bad version number, not '87a' or '89a'\n");
#endif
		return(NULL);
	}

	if (! ReadOK(fd,buf,7))
	{
#if 0
		fprintf(stderr, "failed to read screen descriptor\n");
#endif
		return(NULL);
	}

	GifScreen.Width           = LM_to_uint(buf[0],buf[1]);
	GifScreen.Height          = LM_to_uint(buf[2],buf[3]);
	GifScreen.BitPixel        = 2<<(buf[4]&0x07);
	GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1);
	GifScreen.Background      = buf[5];
	GifScreen.AspectRatio     = buf[6];

	if (BitSet(buf[4], LOCALCOLORMAP)) {	/* Global Colormap */
		if (ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap))
		{
#if 0 
			fprintf(stderr, "error reading global colormap\n");
#endif
			return(NULL);
		}
		for (i=0; i < GifScreen.BitPixel; i++)
		{
			int scale = 65536/MAXCOLORMAPSIZE;

			colrs[i].red = GifScreen.ColorMap[0][i] * scale;
			colrs[i].green = GifScreen.ColorMap[1][i] * scale;
			colrs[i].blue = GifScreen.ColorMap[2][i] * scale;
			colrs[i].pixel = i;
			colrs[i].flags = DoRed|DoGreen|DoBlue;
		}
		for (i = GifScreen.BitPixel; i<MAXCOLORMAPSIZE; i++)
		{
			colrs[i].red = 0;
			colrs[i].green = 0;
			colrs[i].blue = 0;
			colrs[i].pixel = i;
			colrs[i].flags = DoRed|DoGreen|DoBlue;
		}

	}

	if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
		float	r;
		r = ( (float) GifScreen.AspectRatio + 15.0 ) / 64.0;
#if 0
		fprintf(stderr, "Warning:  non-square pixels!\n");
#endif
	}

	for (;;) {
		if (! ReadOK(fd,&c,1))
		{
#if 0
			fprintf(stderr, "EOF / read error on image data\n");
#endif
			return(NULL);
		}

		if (c == ';') {		/* GIF terminator */
			if (imageCount < imageNumber)
			{
#if 0
				fprintf(stderr, "No images found in file\n");
#endif
				return(NULL);
			}
			break;
		}

		if (c == '!') { 	/* Extension */
			if (! ReadOK(fd,&c,1))
			{
#if 0
				fprintf(stderr, "EOF / read error on extention function code\n");
#endif
				return(NULL);
			}
			DoExtension(fd, c);
			continue;
		}

		if (c != ',') {		/* Not a valid start character */
#if 0
			fprintf(stderr, "bogus character 0x%02x, ignoring\n",
				(int)c);
#endif
			continue;
		}

		++imageCount;

		if (! ReadOK(fd,buf,9))
		{
#if 0
			fprintf(stderr,"couldn't read left/top/width/height\n");
#endif
			return(NULL);
		}

		useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);

		bitPixel = 1<<((buf[8]&0x07)+1);

		*w = LM_to_uint(buf[4],buf[5]);
		*h = LM_to_uint(buf[6],buf[7]);
		if (! useGlobalColormap) {
			if (ReadColorMap(fd, bitPixel, localColorMap))
			{
#if 0
				fprintf(stderr, "error reading local colormap\n");
#endif
				return(NULL);
			}
			for (i=0; i < bitPixel; i++)
			{
				int scale = 65536/MAXCOLORMAPSIZE;

				colrs[i].red = localColorMap[0][i] * scale;
				colrs[i].green = localColorMap[1][i] * scale;
				colrs[i].blue = localColorMap[2][i] * scale;
				colrs[i].pixel = i;
				colrs[i].flags = DoRed|DoGreen|DoBlue;
			}
			for (i = bitPixel; i<MAXCOLORMAPSIZE; i++)
			{
				colrs[i].red = 0;
				colrs[i].green = 0;
				colrs[i].blue = 0;
				colrs[i].pixel = i;
				colrs[i].flags = DoRed|DoGreen|DoBlue;
			}
			data = ReadImage(fd, LM_to_uint(buf[4],buf[5]),
				  LM_to_uint(buf[6],buf[7]), localColorMap,
				  BitSet(buf[8], INTERLACE), imageCount != imageNumber);
		} else {
			data = ReadImage(fd, LM_to_uint(buf[4],buf[5]),
				  LM_to_uint(buf[6],buf[7]), GifScreen.ColorMap,
				  BitSet(buf[8], INTERLACE), imageCount != imageNumber);
		}

	}
	return(data);
}

static int
ReadColorMap(fd,number,buffer)
FILE		*fd;
int		number;
unsigned char	buffer[3][MAXCOLORMAPSIZE];
{
	int		i;
	unsigned char	rgb[3];

	for (i = 0; i < number; ++i) {
		if (! ReadOK(fd, rgb, sizeof(rgb)))
		{
#if 0
			fprintf(stderr, "bad colormap\n");
#endif
			return(TRUE);
		}

		buffer[CM_RED][i] = rgb[0] ;
		buffer[CM_GREEN][i] = rgb[1] ;
		buffer[CM_BLUE][i] = rgb[2] ;
	}
	return FALSE;
}

static int
DoExtension(fd, label)
FILE	*fd;
int	label;
{
	static char	buf[256];
	char		*str;

	switch (label) {
	case 0x01:		/* Plain Text Extension */
		str = "Plain Text Extension";
#ifdef notdef
		if (GetDataBlock(fd, (unsigned char*) buf) == 0)
			;

		lpos   = LM_to_uint(buf[0], buf[1]);
		tpos   = LM_to_uint(buf[2], buf[3]);
		width  = LM_to_uint(buf[4], buf[5]);
		height = LM_to_uint(buf[6], buf[7]);
		cellw  = buf[8];
		cellh  = buf[9];
		foreground = buf[10];
		background = buf[11];

		while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
			PPM_ASSIGN(image[ypos][xpos],
					cmap[CM_RED][v],
					cmap[CM_GREEN][v],
					cmap[CM_BLUE][v]);
			++index;
		}

		return FALSE;
#else
		break;
#endif
	case 0xff:		/* Application Extension */
		str = "Application Extension";
		break;
	case 0xfe:		/* Comment Extension */
		str = "Comment Extension";
		while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
			if (showComment)
			{
#if 0
				fprintf(stderr, "gif comment: %s\n", buf);
#endif
			}
		}
		return FALSE;
	case 0xf9:		/* Graphic Control Extension */
		str = "Graphic Control Extension";
		(void) GetDataBlock(fd, (unsigned char*) buf);
		Gif89.disposal    = (buf[0] >> 2) & 0x7;
		Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
		Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
		if ((buf[0] & 0x1) != 0)
			Gif89.transparent = buf[3];

		while (GetDataBlock(fd, (unsigned char*) buf) != 0)
			;
		return FALSE;
	default:
		str = buf;
		sprintf(buf, "UNKNOWN (0x%02x)", label);
		break;
	}

	/* fprintf(stderr, "got a '%s' extension\n", str); */

	while (GetDataBlock(fd, (unsigned char*) buf) != 0)
		;

	return FALSE;
}

int	ZeroDataBlock = FALSE;

static int
GetDataBlock(fd, buf)
FILE		*fd;
unsigned char 	*buf;
{
	unsigned char	count;

	if (! ReadOK(fd,&count,1)) {
#if 0
		fprintf(stderr, "error in getting DataBlock size\n");
#endif
		return -1;
	}

	ZeroDataBlock = count == 0;

	if ((count != 0) && (! ReadOK(fd, buf, count))) {
#if 0
		fprintf(stderr, "error in reading DataBlock\n");
#endif
		return -1;
	}

	return count;
}

static int
GetCode(fd, code_size, flag)
FILE	*fd;
int	code_size;
int	flag;
{
	static unsigned char	buf[280];
	static int		curbit, lastbit, done, last_byte;
	int			i, j, ret;
	unsigned char		count;

	if (flag) {
		curbit = 0;
		lastbit = 0;
		done = FALSE;
		return 0;
	}

	if ( (curbit+code_size) >= lastbit) {
		if (done) {
			if (curbit >= lastbit)
			{
#if 0
				fprintf(stderr, "ran off the end of my bits\n");
#endif
			}
			return -1;
		}
		buf[0] = buf[last_byte-2];
		buf[1] = buf[last_byte-1];

		if ((count = GetDataBlock(fd, &buf[2])) == 0)
			done = TRUE;

		last_byte = 2 + count;
		curbit = (curbit - lastbit) + 16;
		lastbit = (2+count)*8 ;
	}

	ret = 0;
	for (i = curbit, j = 0; j < code_size; ++i, ++j)
	        ret |= ((buf[ i >> 3 ] & (1 << (i % 8))) != 0) << j;

	curbit += code_size;

	return ret;
}

static int
LWZReadByte(fd, flag, input_code_size)
FILE	*fd;
int	flag;
int	input_code_size;
{
	static int	fresh = FALSE;
	int		code, incode;
	static int	code_size, set_code_size;
	static int	max_code, max_code_size;
	static int	firstcode, oldcode;
	static int	clear_code, end_code;
	static int	table[2][(1<< MAX_LWZ_BITS)];
	static int	stack[(1<<(MAX_LWZ_BITS))*2], *sp;
	register int	i;

	if (flag) {
		set_code_size = input_code_size;
		code_size = set_code_size+1;
		clear_code = 1 << set_code_size ;
		end_code = clear_code + 1;
		max_code_size = 2*clear_code;
		max_code = clear_code+2;

		GetCode(fd, 0, TRUE);
		
		fresh = TRUE;

		for (i = 0; i < clear_code; ++i) {
			table[0][i] = 0;
			table[1][i] = i;
		}
		for (; i < (1<<MAX_LWZ_BITS); ++i)
			table[0][i] = table[1][0] = 0;

		sp = stack;

		return 0;
	} else if (fresh) {
		fresh = FALSE;
		do {
			firstcode = oldcode =
				GetCode(fd, code_size, FALSE);
		} while (firstcode == clear_code);
		return firstcode;
	}

	if (sp > stack)
		return *--sp;

	while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
		if (code == clear_code) {
			for (i = 0; i < clear_code; ++i) {
				table[0][i] = 0;
				table[1][i] = i;
			}
			for (; i < (1<<MAX_LWZ_BITS); ++i)
				table[0][i] = table[1][i] = 0;
			code_size = set_code_size+1;
			max_code_size = 2*clear_code;
			max_code = clear_code+2;
			sp = stack;
			firstcode = oldcode =
					GetCode(fd, code_size, FALSE);
			return firstcode;
		} else if (code == end_code) {
			int		count;
			unsigned char	buf[260];

			if (ZeroDataBlock)
				return -2;

			while ((count = GetDataBlock(fd, buf)) > 0)
				;

#if 0
			if (count != 0)
				fprintf(stderr, "missing EOD in data stream (common occurence)\n");
#endif
			return -2;
		}

		incode = code;

		if (code >= max_code) {
			*sp++ = firstcode;
			code = oldcode;
		}

		while (code >= clear_code) {
			*sp++ = table[1][code];
			if (code == table[0][code])
			{
#if 0
				fprintf(stderr, "circular table entry BIG ERROR\n");
#endif
				return(code);
			}
			code = table[0][code];
		}

		*sp++ = firstcode = table[1][code];

		if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
			table[0][code] = oldcode;
			table[1][code] = firstcode;
			++max_code;
			if ((max_code >= max_code_size) &&
				(max_code_size < (1<<MAX_LWZ_BITS))) {
				max_code_size *= 2;
				++code_size;
			}
		}

		oldcode = incode;

		if (sp > stack)
			return *--sp;
	}
	return code;
}

static unsigned char *
ReadImage(fd, len, height, cmap, interlace, ignore)
FILE	*fd;
int	len, height;
unsigned char	cmap[3][MAXCOLORMAPSIZE];
int	interlace, ignore;
{
	unsigned char	c;	
	int		v;
	int		xpos = 0, ypos = 0, pass = 0;
/*
	pixel		**image;
*/
	unsigned char 	*data;
	unsigned char 	*dptr;

	/*
	**  Initialize the Compression routines
	*/
	if (! ReadOK(fd,&c,1))
	{
#if 0
		fprintf(stderr, "EOF / read error on image data\n");
#endif
		return(NULL);
	}

	if (LWZReadByte(fd, TRUE, c) < 0)
	{
#if 0
		fprintf(stderr, "error reading image\n");
#endif
		return(NULL);
	}

	/*
	**  If this is an "uninteresting picture" ignore it.
	*/
	if (ignore) {
#if 0
		if (verbose)
			fprintf(stderr, "skipping image...\n" );
#endif
		while (LWZReadByte(fd, FALSE, c) >= 0)
			;
		return NULL;
	}

/*
	if ((image = ppm_allocarray(len, height)) == NULL)
	{
		fprintf(stderr, "couldn't alloc space for image\n");
		return(NULL);
	}
*/

	data = (unsigned char *)XtMalloc(len * height);
	if (data == NULL)
	{
#if 0
		fprintf(stderr, "Cannot allocate space for image data\n");
#endif
		return(NULL);
	}

#if 0
	if (verbose)
		fprintf(stderr, "reading %d by %d%s GIF image\n",
#endif			len, height, interlace ? " interlaced" : "" );

	while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
		dptr = (unsigned char *)(data + (ypos * len) + xpos);
		*dptr = (unsigned char)v;
/*
		PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v],
					cmap[CM_GREEN][v], cmap[CM_BLUE][v]);
*/

		++xpos;
		if (xpos == len) {
			xpos = 0;
			if (interlace) {
				switch (pass) {
				case 0:
				case 1:
					ypos += 8; break;
				case 2:
					ypos += 4; break;
				case 3:
					ypos += 2; break;
				}

				if (ypos >= height) {
					++pass;
					switch (pass) {
					case 1:
						ypos = 4; break;
					case 2:
						ypos = 2; break;
					case 3:
						ypos = 1; break;
					default:
						goto fini;
					}
				}
			} else {
				++ypos;
			}
		}
		if (ypos >= height)
			break;
	}

fini:
#if 0
	if (LWZReadByte(fd,FALSE,c)>=0)
		fprintf(stderr, "too much input data, ignoring extra...\n");
#endif

/*
	if (verbose)
		pm_message("writing output");
	ppm_writeppm(stdout, image, len, height, (pixval) 255, 0 );
*/
	return(data);
}

/* 
 * ******* end required file <gifread.inc> *******
 */
/* 
 * ******* begin required file <xpmread.inc> *******
 */
/****************************************************************************
 * NCSA Mosaic for the X Window System                                      *
 * Software Development Group                                               *
 * National Center for Supercomputing Applications                          *
 * University of Illinois at Urbana-Champaign                               *
 * 605 E. Springfield, Champaign IL 61820                                   *
 * mosaic@ncsa.uiuc.edu                                                     *
 *                                                                          *
 * Copyright (C) 1993, Board of Trustees of the University of Illinois      *
 *                                                                          *
 * NCSA Mosaic software, both binary and source (hereafter, Software) is    *
 * copyrighted by The Board of Trustees of the University of Illinois       *
 * (UI), and ownership remains with the UI.                                 *
 *                                                                          *
 * The UI grants you (hereafter, Licensee) a license to use the Software    *
 * for academic, research and internal business purposes only, without a    *
 * fee.  Licensee may distribute the binary and source code (if released)   *
 * to third parties provided that the copyright notice and this statement   *
 * appears on all copies and that no charge is associated with such         *
 * copies.                                                                  *
 *                                                                          *
 * Licensee may make derivative works.  However, if Licensee distributes    *
 * any derivative work based on or derived from the Software, then          *
 * Licensee will (1) notify NCSA regarding its distribution of the          *
 * derivative work, and (2) clearly notify users that such derivative       *
 * work is a modified version and not the original NCSA Mosaic              *
 * distributed by the UI.                                                   *
 *                                                                          *
 * Any Licensee wishing to make commercial use of the Software should       *
 * contact the UI, c/o NCSA, to negotiate an appropriate license for such   *
 * commercial use.  Commercial use includes (1) integration of all or       *
 * part of the source code into a product for sale or license by or on      *
 * behalf of Licensee to third parties, or (2) distribution of the binary   *
 * code or source code to third parties that need it to utilize a           *
 * commercial product sold or licensed by or on behalf of Licensee.         *
 *                                                                          *
 * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR   *
 * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED          *
 * WARRANTY.  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE    *
 * USERS OF THIS SOFTWARE.                                                  *
 *                                                                          *
 * By using or copying this Software, Licensee agrees to abide by the       *
 * copyright law and all other applicable laws of the U.S. including, but   *
 * not limited to, export control laws, and the terms of this license.      *
 * UI shall have the right to terminate this license immediately by         *
 * written notice upon Licensee's breach of, or non-compliance with, any    *
 * of its terms.  Licensee may be held legally responsible for any          *
 * copyright infringement that is caused or encouraged by Licensee's        *
 * failure to abide by the terms of this license.                           *
 *                                                                          *
 * Comments and questions are welcome and can be sent to                    *
 * mosaic-x@ncsa.uiuc.edu.                                                  *
 ****************************************************************************/
/*
 * The following XPM reading code was based on the libXpm code, which I
 * am free to use as long as I include the following copyright:
 */
/*
 * Copyright 1990-93 GROUPE BULL
 *
 * 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 notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of GROUPE BULL not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission.  GROUPE BULL makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * GROUPE BULL disclaims all warranties with regard to this software,
 * including all implied warranties of merchantability and fitness,
 * in no event shall GROUPE BULL be liable for any special,
 * indirect or consequential damages or any damages
 * whatsoever resulting from loss of use, data or profits,
 * whether in an action of contract, negligence or other tortious
 * action, arising out of or in connection with the use 
 * or performance of this software.
 *
 */

#ifdef TIMING
#include <sys/time.h>
struct timeval Tv;
struct timezone Tz;
#endif
/*
#include "mosaic.h"
*/
#include <X11/Xos.h>
#include "html-xpm.h"

extern Display *dsp;


char *xpmColorKeys[] = {
    "s",				/* key #1: symbol */
    "m",				/* key #2: mono visual */
    "g4",				/* key #3: 4 grays visual */
    "g",				/* key #4: gray visual */
    "c",				/* key #5: color visual */
};

xpmDataType xpmDataTypes[] =
{
    "", "!", "\n", '\0', '\n', "", "", "", "",	/* Natural type */
    "C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n",
    "Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n",
#ifdef VMS
    NULL
#else
    NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL
#endif
};


#ifndef XPM
/*
 * Free the computed color table
 */
void
xpmFreeColorTable(colorTable, ncolors)
    char ***colorTable;
    int ncolors;
{
    int a, b;
    char ***ct, **cts;

    if (colorTable) {
	for (a = 0, ct = colorTable; a < ncolors; a++, ct++)
	    if (*ct) {
		for (b = 0, cts = *ct; b <= NKEYS; b++, cts++)
		    if (*cts)
			XpmFree(*cts);
		XpmFree(*ct);
	    }
	XpmFree(colorTable);
    }
}


/*
 * Intialize the xpmInternAttrib pointers to Null to know
 * which ones must be freed later on.
 */
void
xpmInitInternAttrib(attrib)
    xpmInternAttrib *attrib;
{
    attrib->ncolors = 0;
    attrib->colorTable = NULL;
    attrib->pixelindex = NULL;
    attrib->xcolors = NULL;
    attrib->colorStrings = NULL;
    attrib->mask_pixel = UNDEF_PIXEL;
}


/*
 * Free the xpmInternAttrib pointers which have been allocated
 */
void
xpmFreeInternAttrib(attrib)
    xpmInternAttrib *attrib;
{
    unsigned int a, ncolors;
    char **sptr;

    if (attrib->colorTable)
	xpmFreeColorTable(attrib->colorTable, attrib->ncolors);
    if (attrib->pixelindex)
	XpmFree(attrib->pixelindex);
    if (attrib->xcolors)
	XpmFree(attrib->xcolors);
    if (attrib->colorStrings) {
	ncolors = attrib->ncolors;
	for (a = 0, sptr = attrib->colorStrings; a < ncolors; a++, sptr++)
	    if (*sptr)
		XpmFree(*sptr);
	XpmFree(attrib->colorStrings);
    }
}
#endif


/*
 * open the given file to be read as an xpmData which is returned.
 */
int
xpmReadFile(filename, mdata)
    char *filename;
    xpmData *mdata;
{
#ifdef ZPIPE
    char *compressfile, buf[BUFSIZ];
    struct stat status;

#endif

    if (!filename) {
	mdata->stream.file = (stdin);
	mdata->type = XPMFILE;
    } else {
#ifdef ZPIPE
	if ((strlen(filename) > 2) &&
	    !strcmp(".Z", filename + (strlen(filename) - 2))) {
	    mdata->type = XPMPIPE;
	    sprintf(buf, "uncompress -c %s", filename);
	    if (!(mdata->stream.file = popen(buf, "r")))
		return (XpmOpenFailed);

	} else if ((strlen(filename) > 2) &&
		   !strcmp(".z", filename + (strlen(filename) - 2))) {
	    mdata->type = XPMPIPE;
	    sprintf(buf, "gunzip -c %s", filename);
	    if (!(mdata->stream.file = popen(buf, "r")))
		return (XpmOpenFailed);

	} else {
	    if (!(compressfile = (char *) XpmMalloc(strlen(filename) + 3)))
		return (XpmNoMemory);

	    strcpy(compressfile, filename);
	    strcat(compressfile, ".Z");
	    if (!stat(compressfile, &status)) {
		sprintf(buf, "uncompress -c %s", compressfile);
		if (!(mdata->stream.file = popen(buf, "r"))) {
		    XpmFree(compressfile);
		    return (XpmOpenFailed);
		}
		mdata->type = XPMPIPE;
	    } else {
		strcpy(compressfile, filename);
		strcat(compressfile, ".z");
		if (!stat(compressfile, &status)) {
		    sprintf(buf, "gunzip -c %s", compressfile);
		    if (!(mdata->stream.file = popen(buf, "r"))) {
			XpmFree(compressfile);
			return (XpmOpenFailed);
		    }
		    mdata->type = XPMPIPE;
		} else {
#endif
		    if (!(mdata->stream.file = fopen(filename, "r"))) {
#ifdef ZPIPE
			XpmFree(compressfile);
#endif
			return (XpmOpenFailed);
		    }
		    mdata->type = XPMFILE;
#ifdef ZPIPE
		}
	    }
	    XpmFree(compressfile);
	}
#endif
    }
    mdata->CommentLength = 0;
    return (XpmSuccess);
}


/*
 * close the file related to the xpmData if any
 */
int 
xpmDataClose(mdata)
    xpmData *mdata;
{
    switch (mdata->type) {
    case XPMARRAY:
    case XPMBUFFER:
	break;
    case XPMFILE:
	if (mdata->stream.file != (stdout) && mdata->stream.file != (stdin))
	    fclose(mdata->stream.file);
	break;
#ifdef ZPIPE
    case XPMPIPE:
	pclose(mdata->stream.file);
	break;
#endif
    }
    return 0;
}


static int
ParseComment(mdata)
    xpmData *mdata;
{
    if (mdata->type == XPMBUFFER) {
	register char c;
	register unsigned int n = 0;
	unsigned int notend;
	char *s, *s2;

	s = mdata->Comment;
	*s = mdata->Bcmt[0];

	/* skip the string beginning comment */
	s2 = mdata->Bcmt;
	do {
	    c = *mdata->cptr++;
	    *++s = c;
	    n++;
	    s2++;
	} while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);

	if (*s2 != '\0') {
	    /* this wasn't the beginning of a comment */
	    mdata->cptr -= n;
	    return 0;
	}
	/* store comment */
	mdata->Comment[0] = *s;
	s = mdata->Comment;
	notend = 1;
	n = 0;
	while (notend) {
	    s2 = mdata->Ecmt;
	    while (*s != *s2 && c && c != mdata->Bos) {
		c = *mdata->cptr++;
		*++s = c;
		n++;
	    }
	    mdata->CommentLength = n;
	    do {
		c = *mdata->cptr++;
		n++;
		*++s = c;
		s2++;
	    } while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);
	    if (*s2 == '\0') {
		/* this is the end of the comment */
		notend = 0;
		mdata->cptr--;
	    }
	}
	return 0;
    } else {
	FILE *file = mdata->stream.file;
	register int c;
	register unsigned int n = 0, a;
	unsigned int notend;
	char *s, *s2;

	s = mdata->Comment;
	*s = mdata->Bcmt[0];

	/* skip the string beginning comment */
	s2 = mdata->Bcmt;
	do {
	    c = getc(file);
	    *++s = c;
	    n++;
	    s2++;
	} while (c == *s2 && *s2 != '\0'
		 && c != EOF && c != mdata->Bos);

	if (*s2 != '\0') {
	    /* this wasn't the beginning of a comment */
	    /* put characters back in the order that we got them */
	    for (a = n; a > 0; a--, s--)
		ungetc(*s, file);
	    return 0;
	}
	/* store comment */
	mdata->Comment[0] = *s;
	s = mdata->Comment;
	notend = 1;
	n = 0;
	while (notend) {
	    s2 = mdata->Ecmt;
	    while (*s != *s2 && c != EOF && c != mdata->Bos) {
		c = getc(file);
		*++s = c;
		n++;
	    }
	    mdata->CommentLength = n;
	    do {
		c = getc(file);
		n++;
		*++s = c;
		s2++;
	    } while (c == *s2 && *s2 != '\0'
		     && c != EOF && c != mdata->Bos);
	    if (*s2 == '\0') {
		/* this is the end of the comment */
		notend = 0;
		ungetc(*s, file);
	    }
	}
	return 0;
    }
}


/*
 * skip to the end of the current string and the beginning of the next one
 */
int 
xpmNextString(mdata)
    xpmData *mdata;
{
    if (!mdata->type)
	mdata->cptr = (mdata->stream.data)[++mdata->line];
    else if (mdata->type == XPMBUFFER) {
	register char c;

	/* get to the end of the current string */
	if (mdata->Eos)
	    while ((c = *mdata->cptr++) && c != mdata->Eos);

	/*
	 * then get to the beginning of the next string looking for possible
	 * comment
	 */
	if (mdata->Bos) {
	    while ((c = *mdata->cptr++) && c != mdata->Bos)
		if (mdata->Bcmt && c == mdata->Bcmt[0])
		    ParseComment(mdata);
	} else if (mdata->Bcmt) {	/* XPM2 natural */
	    while ((c = *mdata->cptr++) == mdata->Bcmt[0])
		ParseComment(mdata);
	    mdata->cptr--;
	}
    } else {
	register int c;
	FILE *file = mdata->stream.file;

	/* get to the end of the current string */
	if (mdata->Eos)
	    while ((c = getc(file)) != mdata->Eos && c != EOF);

	/*
	 * then get to the beginning of the next string looking for possible
	 * comment
	 */
	if (mdata->Bos) {
	    while ((c = getc(file)) != mdata->Bos && c != EOF)
		if (mdata->Bcmt && c == mdata->Bcmt[0])
		    ParseComment(mdata);

	} else if (mdata->Bcmt) {	/* XPM2 natural */
	    while ((c = getc(file)) == mdata->Bcmt[0])
		ParseComment(mdata);
	    ungetc(c, file);
	}
    }
    return 0;
}


unsigned int
atoui(p, l, ui_return)
    register char *p;
    unsigned int l;
    unsigned int *ui_return;
{
    register int n, i;

    n = 0;
    for (i = 0; i < l; i++)
	if (*p >= '0' && *p <= '9')
	    n = n * 10 + *p++ - '0';
	else
	    break;

    if (i != 0 && i == l) {
	*ui_return = n;
	return 1;
    } else
	return 0;
}


static int
ParseValues(data, width, height, ncolors, cpp,
	    x_hotspot, y_hotspot, hotspot, extensions)
    xpmData *data;
    unsigned int *width, *height, *ncolors, *cpp;
    unsigned int *x_hotspot, *y_hotspot, *hotspot;
    unsigned int *extensions;
{
    unsigned int l;
    char buf[BUFSIZ];

    /*
     * read values: width, height, ncolors, chars_per_pixel
     */
    if (!(xpmNextUI(data, width) && xpmNextUI(data, height)
	  && xpmNextUI(data, ncolors) && xpmNextUI(data, cpp)))
	return (XpmFileInvalid);

    /*
     * read optional information (hotspot and/or XPMEXT) if any
     */
    l = xpmNextWord(data, buf);
    if (l) {
	*extensions = l == 6 && !strncmp("XPMEXT", buf, 6);
	if (*extensions)
	    *hotspot = xpmNextUI(data, x_hotspot)
		&& xpmNextUI(data, y_hotspot);
	else {
	    *hotspot = atoui(buf, l, x_hotspot) && xpmNextUI(data, y_hotspot);
	    l = xpmNextWord(data, buf);
	    *extensions = l == 6 && !strncmp("XPMEXT", buf, 6);
	}
    }
    return (XpmSuccess);
}

static int
ParseColors(data, ncolors, cpp, colorTablePtr, hashtable)
    xpmData *data;
    unsigned int ncolors;
    unsigned int cpp;
    char ****colorTablePtr;		/* Jee, that's something! */
    xpmHashTable *hashtable;
{
    unsigned int key, l, a, b;
    unsigned int curkey;		/* current color key */
    unsigned int lastwaskey;		/* key read */
    char buf[BUFSIZ];
    char curbuf[BUFSIZ];		/* current buffer */
    char ***ct, **cts, **sptr, *s;
    char ***colorTable;
    int ErrorStatus;

    colorTable = (char ***) XpmCalloc(ncolors, sizeof(char **));
    if (!colorTable)
	return (XpmNoMemory);

    for (a = 0, ct = colorTable; a < ncolors; a++, ct++) {
	xpmNextString(data);		/* skip the line */
	cts = *ct = (char **) XpmCalloc((NKEYS + 1), sizeof(char *));
	if (!cts) {
	    xpmFreeColorTable(colorTable, ncolors);
	    return (XpmNoMemory);
	}

	/*
	 * read pixel value
	 */
	*cts = (char *) XpmMalloc(cpp + 1);	/* + 1 for null terminated */
	if (!*cts) {
	    xpmFreeColorTable(colorTable, ncolors);
	    return (XpmNoMemory);
	}
	for (b = 0, s = *cts; b < cpp; b++, s++)
	    *s = xpmGetC(data);
	*s = '\0';

	/*
	 * store the string in the hashtable with its color index number
	 */
	if (USE_HASHTABLE) {
	    ErrorStatus = xpmHashIntern(hashtable, *cts, HashAtomData(a));
	    if (ErrorStatus != XpmSuccess) {
		xpmFreeColorTable(colorTable, ncolors);
		return (ErrorStatus);
	    }
	}

	/*
	 * read color keys and values
	 */
	curkey = 0;
	lastwaskey = 0;
	while (l = xpmNextWord(data, buf)) {
	    if (!lastwaskey) {
		for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++, sptr++)
		    if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
			break;
	    }
	    if (!lastwaskey && key < NKEYS) {	/* open new key */
		if (curkey) {		/* flush string */
		    s = cts[curkey] = (char *) XpmMalloc(strlen(curbuf) + 1);
		    if (!s) {
			xpmFreeColorTable(colorTable, ncolors);
			return (XpmNoMemory);
		    }
		    strcpy(s, curbuf);
		}
		curkey = key + 1;	/* set new key  */
		*curbuf = '\0';		/* reset curbuf */
		lastwaskey = 1;
	    } else {
		if (!curkey) {		/* key without value */
		    xpmFreeColorTable(colorTable, ncolors);
		    return (XpmFileInvalid);
		}
		if (!lastwaskey)
		    strcat(curbuf, " ");/* append space */
		buf[l] = '\0';
		strcat(curbuf, buf);	/* append buf */
		lastwaskey = 0;
	    }
	}
	if (!curkey) {			/* key without value */
	    xpmFreeColorTable(colorTable, ncolors);
	    return (XpmFileInvalid);
	}
	s = cts[curkey] = (char *) XpmMalloc(strlen(curbuf) + 1);
	if (!s) {
	    xpmFreeColorTable(colorTable, ncolors);
	    return (XpmNoMemory);
	}
	strcpy(s, curbuf);
    }
    *colorTablePtr = colorTable;
    return (XpmSuccess);
}

static int
ParsePixels(data, width, height, ncolors, cpp, colorTable, hashtable, pixels)
    xpmData *data;
    unsigned int width;
    unsigned int height;
    unsigned int ncolors;
    unsigned int cpp;
    char ***colorTable;
    xpmHashTable *hashtable;
    unsigned int **pixels;
{
    unsigned int *iptr, *iptr2;
    unsigned int a, x, y;

    iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height);
    if (!iptr2)
	return (XpmNoMemory);

    iptr = iptr2;

    switch (cpp) {

    case (1):				/* Optimize for single character
					 * colors */
	{
	    unsigned short colidx[256];

	    bzero(colidx, 256 * sizeof(short));
	    for (a = 0; a < ncolors; a++)
		colidx[colorTable[a][0][0]] = a + 1;

	    for (y = 0; y < height; y++) {
		xpmNextString(data);
		for (x = 0; x < width; x++, iptr++) {
		    int idx = colidx[xpmGetC(data)];

		    if (idx != 0)
			*iptr = idx - 1;
		    else {
			XpmFree(iptr2);
			return (XpmFileInvalid);
		    }
		}
	    }
	}
	break;

    case (2):				/* Optimize for double character
					 * colors */
	{
	    unsigned short cidx[256][256];

	    bzero(cidx, 256 * 256 * sizeof(short));
	    for (a = 0; a < ncolors; a++)
		cidx[colorTable[a][0][0]][colorTable[a][0][1]] = a + 1;

	    for (y = 0; y < height; y++) {
		xpmNextString(data);
		for (x = 0; x < width; x++, iptr++) {
		    int cc1 = xpmGetC(data);
		    int idx = cidx[cc1][xpmGetC(data)];

		    if (idx != 0)
			*iptr = idx - 1;
		    else {
			XpmFree(iptr2);
			return (XpmFileInvalid);
		    }
		}
	    }
	}
	break;

    default:				/* Non-optimized case of long color
					 * names */
	{
	    char *s;
	    char buf[BUFSIZ];

	    buf[cpp] = '\0';
	    if (USE_HASHTABLE) {
		xpmHashAtom *slot;

		for (y = 0; y < height; y++) {
		    xpmNextString(data);
		    for (x = 0; x < width; x++, iptr++) {
			for (a = 0, s = buf; a < cpp; a++, s++)
			    *s = xpmGetC(data);
			slot = xpmHashSlot(hashtable, buf);
			if (!*slot) {	/* no color matches */
			    XpmFree(iptr2);
			    return (XpmFileInvalid);
			}
			*iptr = HashColorIndex(slot);
		    }
		}
	    } else {
		for (y = 0; y < height; y++) {
		    xpmNextString(data);
		    for (x = 0; x < width; x++, iptr++) {
			for (a = 0, s = buf; a < cpp; a++, s++)
			    *s = xpmGetC(data);
			for (a = 0; a < ncolors; a++)
			    if (!strcmp(colorTable[a][0], buf))
				break;
			if (a == ncolors) {	/* no color matches */
			    XpmFree(iptr2);
			    return (XpmFileInvalid);
			}
			*iptr = a;
		    }
		}
	    }
	}
	break;
    }
    *pixels = iptr2;
    return (XpmSuccess);
}


/*
 * skip whitespace and return the following word
 */
unsigned int
xpmNextWord(mdata, buf)
    xpmData *mdata;
    char *buf;
{
    register unsigned int n = 0;
    int c;

    if (!mdata->type || mdata->type == XPMBUFFER) {
	while (isspace(c = *mdata->cptr) && c != mdata->Eos)
	    mdata->cptr++;
	do {
	    c = *mdata->cptr++;
	    *buf++ = c;
	    n++;
	} while (!isspace(c) && c != mdata->Eos);
	n--;
	mdata->cptr--;
    } else {
	FILE *file = mdata->stream.file;

	while ((c = getc(file)) != EOF && isspace(c) && c != mdata->Eos);
	while (!isspace(c) && c != mdata->Eos && c != EOF) {
	    *buf++ = c;
	    n++;
	    c = getc(file);
	}
	ungetc(c, file);
    }
    return (n);
}


/*
 * skip whitespace and compute the following unsigned int,
 * returns 1 if one is found and 0 if not
 */
int
xpmNextUI(mdata, ui_return)
    xpmData *mdata;
    unsigned int *ui_return;
{
    char buf[BUFSIZ];
    int l;

    l = xpmNextWord(mdata, buf);
    return atoui(buf, l, ui_return);
}


/*
 * parse xpm header
 */
int 
xpmParseHeader(mdata)
    xpmData *mdata;
{
    char buf[BUFSIZ];
    int l, n = 0;

    if (mdata->type) {
	mdata->Bos = '\0';
	mdata->Eos = '\n';
	mdata->Bcmt = mdata->Ecmt = NULL;
	xpmNextWord(mdata, buf);	/* skip the first word */
	l = xpmNextWord(mdata, buf);	/* then get the second word */
	if ((l == 3 && !strncmp("XPM", buf, 3)) ||
	    (l == 4 && !strncmp("XPM2", buf, 4))) {
	    if (l == 3)
		n = 1;			/* handle XPM as XPM2 C */
	    else {
		l = xpmNextWord(mdata, buf);	/* get the type key word */

		/*
		 * get infos about this type
		 */
		while (xpmDataTypes[n].type
		       && strncmp(xpmDataTypes[n].type, buf, l))
		    n++;
	    }
	    if (xpmDataTypes[n].type) {
		if (n == 0) {		/* natural type */
		    mdata->Bcmt = xpmDataTypes[n].Bcmt;
		    mdata->Ecmt = xpmDataTypes[n].Ecmt;
		    xpmNextString(mdata);	/* skip the end of
						 * headerline */
		    mdata->Bos = xpmDataTypes[n].Bos;
		} else {
		    xpmNextString(mdata);	/* skip the end of
						 * headerline */
		    mdata->Bcmt = xpmDataTypes[n].Bcmt;
		    mdata->Ecmt = xpmDataTypes[n].Ecmt;
		    mdata->Bos = xpmDataTypes[n].Bos;
		    mdata->Eos = '\0';
		    xpmNextString(mdata);	/* skip the assignment line */
		}
		mdata->Eos = xpmDataTypes[n].Eos;
	    } else
		return XpmFileInvalid;
	} else
	    return XpmFileInvalid;
    }
    return XpmSuccess;
}


/*
 * get the current comment line
 */
int 
xpmGetCmt(mdata, cmt)
    xpmData *mdata;
    char **cmt;
{
    if (!mdata->type)
	*cmt = NULL;
    else if (mdata->CommentLength) {
	*cmt = (char *) XpmMalloc(mdata->CommentLength + 1);
	strncpy(*cmt, mdata->Comment, mdata->CommentLength);
	(*cmt)[mdata->CommentLength] = '\0';
	mdata->CommentLength = 0;
    } else
	*cmt = NULL;
    return 0;
}


#undef RETURN
#define RETURN(status) \
  { if (colorTable) xpmFreeColorTable(colorTable, ncolors); \
    if (pixelindex) XpmFree(pixelindex); \
    if (hints_cmt)  XpmFree(hints_cmt); \
    if (colors_cmt) XpmFree(colors_cmt); \
    if (pixels_cmt) XpmFree(pixels_cmt); \
    return(status); }

/*
 * This function parses an Xpm file or data and store the found informations
 * in an an xpmInternAttrib structure which is returned.
 */
int
xpmParseData(data, attrib_return, attributes)
    xpmData *data;
    xpmInternAttrib *attrib_return;
    XpmAttributes *attributes;
{
    /* variables to return */
    unsigned int width, height, ncolors, cpp;
    unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0;
    char ***colorTable = NULL;
    unsigned int *pixelindex = NULL;
    char *hints_cmt = NULL;
    char *colors_cmt = NULL;
    char *pixels_cmt = NULL;

    int ErrorStatus;
    xpmHashTable hashtable;

    /*
     * parse the header
     */
    ErrorStatus = xpmParseHeader(data);
    if (ErrorStatus != XpmSuccess)
	return (ErrorStatus);

    /*
     * read values
     */
    ErrorStatus = ParseValues(data, &width, &height, &ncolors, &cpp,
			    &x_hotspot, &y_hotspot, &hotspot, &extensions);
    if (ErrorStatus != XpmSuccess)
	return (ErrorStatus);

    /*
     * store the hints comment line
     */
    if (attributes && (attributes->valuemask & XpmReturnInfos))
	xpmGetCmt(data, &hints_cmt);

    /*
     * init the hastable
     */
    if (USE_HASHTABLE) {
	ErrorStatus = xpmHashTableInit(&hashtable);
	if (ErrorStatus != XpmSuccess)
	    return (ErrorStatus);
    }

    /*
     * read colors
     */
    ErrorStatus = ParseColors(data, ncolors, cpp, &colorTable, &hashtable);
    if (ErrorStatus != XpmSuccess)
	RETURN(ErrorStatus);

    /*
     * store the colors comment line
     */
    if (attributes && (attributes->valuemask & XpmReturnInfos))
	xpmGetCmt(data, &colors_cmt);

    /*
     * read pixels and index them on color number
     */
    ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
			      &hashtable, &pixelindex);

    /*
     * free the hastable
     */
    if (USE_HASHTABLE)
	xpmHashTableFree(&hashtable);

    if (ErrorStatus != XpmSuccess)
	RETURN(ErrorStatus);

    /*
     * store the pixels comment line
     */
    if (attributes && (attributes->valuemask & XpmReturnInfos))
	xpmGetCmt(data, &pixels_cmt);

    /*
     * store found informations in the xpmInternAttrib structure
     */
    attrib_return->width = width;
    attrib_return->height = height;
    attrib_return->cpp = cpp;
    attrib_return->ncolors = ncolors;
    attrib_return->colorTable = colorTable;
    attrib_return->pixelindex = pixelindex;

    if (attributes) {
	if (attributes->valuemask & XpmReturnInfos) {
	    attributes->hints_cmt = hints_cmt;
	    attributes->colors_cmt = colors_cmt;
	    attributes->pixels_cmt = pixels_cmt;
	}
	if (hotspot) {
	    attributes->x_hotspot = x_hotspot;
	    attributes->y_hotspot = y_hotspot;
	    attributes->valuemask |= XpmHotspot;
	}
    }
    return (XpmSuccess);
}

/*
 * open the given array to be read or written as an xpmData which is returned
 */
void
xpmOpenArray(data, mdata)
    char **data;
    xpmData *mdata;
{
    mdata->type = XPMARRAY;
    mdata->stream.data = data;
    mdata->cptr = *data;
    mdata->line = 0;
    mdata->CommentLength = 0;
    mdata->Bcmt = mdata->Ecmt = NULL;
    mdata->Bos = mdata->Eos = '\0';
}


unsigned char *ReadXpm3Pixmap(view,fp, datafile, w, h, colrs, bg)
Widget view;
FILE *fp;
char *datafile;
int *w, *h;
XColor *colrs;
int *bg;
{
	xpmData mdata;
	XpmAttributes attributes;
	xpmInternAttrib attrib;
	int ErrorStatus;
	int Colors;
	XColor tmpcolr;
	int i, j;
	char **colorStrings;
	char *colorName;
	unsigned char *pix_data;
	unsigned char *bptr;
	unsigned int *pixels;
/*        extern Widget view;*/
#ifdef TIMING
gettimeofday(&Tv, &Tz);
fprintf(stderr, "ReadXpm3Pixmap enter (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
#endif

	*w = 0;
	*h = 0;

	attributes.valuemask = XpmReturnPixels;

	if ((ErrorStatus = xpmReadFile(datafile, &mdata)) != XpmSuccess)
	{
		return(NULL);
	}

	xpmInitInternAttrib(&attrib);

	ErrorStatus = xpmParseData(&mdata, &attrib, &attributes);
	if (ErrorStatus != XpmSuccess)
	{
		xpmFreeInternAttrib(&attrib);
		xpmDataClose(&mdata);
		return(NULL);
	}

	*w = (int)attrib.width;
	*h = (int)attrib.height;
	Colors = (int)attrib.ncolors;

	for (i=0; i<Colors; i++)
	{
		colorStrings = attrib.colorTable[i];
		colorName = colorStrings[NKEYS];
		if (strcmp(colorName, TRANSPARENT_COLOR) == 0)
		{
			unsigned long bg_pixel;

			/* First, go fetch the pixel. */
			XtVaGetValues (view, XtNbackground, &bg_pixel, NULL);

			/* Now, load up tmpcolr. */
			tmpcolr.pixel = bg_pixel;

			/* Now query for the full color info. */
			XQueryColor (XtDisplay (view), 
				DefaultColormap (XtDisplay (view),
				DefaultScreen (XtDisplay (view))),
			       &tmpcolr);
			*bg = i;
		}
		else
		{
		  Display *dsp = XtDisplay(view);
			XParseColor(dsp,
				DefaultColormap(dsp, DefaultScreen(dsp)),
				colorName, &tmpcolr);
		}
		colrs[i].red = tmpcolr.red;
		colrs[i].green = tmpcolr.green;
		colrs[i].blue = tmpcolr.blue;
		colrs[i].pixel = i;
		colrs[i].flags = DoRed|DoGreen|DoBlue;
	}
	for (i=Colors; i<256; i++)
	{
		colrs[i].red = 0;
		colrs[i].green = 0;
		colrs[i].blue = 0;
		colrs[i].pixel = i;
		colrs[i].flags = DoRed|DoGreen|DoBlue;
	}

	pixels = attrib.pixelindex;
	pix_data = (unsigned char *)malloc((*w) * (*h));
        if (pix_data == NULL)
        {
                fprintf(stderr, "Not enough memory for data.\n");
		xpmFreeInternAttrib(&attrib);
		xpmDataClose(&mdata);
                return((unsigned char *)NULL);
        }
	bptr = pix_data;
        for (i=0; i<((*w) * (*h)); i++)
        {
		int pix;

		pix = (int)*pixels;
                if (pix > (256 - 1))
                        pix = 0;
		*bptr++ = (unsigned char)pix;
                pixels++;
        }

	xpmFreeInternAttrib(&attrib);
	xpmDataClose(&mdata);

#ifdef TIMING
gettimeofday(&Tv, &Tz);
fprintf(stderr, "ReadXpm3Pixmap exit (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
#endif
        return(pix_data);
}


unsigned char *ProcessXpm3Data(wid, xpmdata, w, h, colrs, bg)
Widget wid;
char **xpmdata;
int *w, *h;
XColor *colrs;
int *bg;
{
	xpmData mdata;
	XpmAttributes attributes;
	xpmInternAttrib attrib;
	int ErrorStatus;
	int Colors;
	XColor tmpcolr;
	int i, j;
	char **colorStrings;
	char *colorName;
	unsigned char *pix_data;
	unsigned char *bptr;
	unsigned int *pixels;
        extern Widget view;

	*w = 0;
	*h = 0;

	attributes.valuemask = XpmReturnPixels;

	xpmOpenArray(xpmdata, &mdata);
	xpmInitInternAttrib(&attrib);

	ErrorStatus = xpmParseData(&mdata, &attrib, &attributes);
	if (ErrorStatus != XpmSuccess)
	{
		xpmFreeInternAttrib(&attrib);
		xpmDataClose(&mdata);
		return(NULL);
	}

	*w = (int)attrib.width;
	*h = (int)attrib.height;
	Colors = (int)attrib.ncolors;

	for (i=0; i<Colors; i++)
	{
		colorStrings = attrib.colorTable[i];
		colorName = colorStrings[NKEYS];
		if (strcmp(colorName, TRANSPARENT_COLOR) == 0)
		{
			unsigned long bg_pixel;

			/* First, go fetch the pixel. */
			XtVaGetValues (wid, XtNbackground, &bg_pixel, NULL);

			/* Now, load up tmpcolr. */
			tmpcolr.pixel = bg_pixel;

			/* Now query for the full color info. */
			XQueryColor (XtDisplay (wid), 
				DefaultColormap (XtDisplay (wid),
				DefaultScreen (XtDisplay (wid))),
			       &tmpcolr);
			*bg = i;
		}
		else
		{
			XParseColor(XtDisplay (wid),
				DefaultColormap(XtDisplay (wid),
				DefaultScreen(XtDisplay (wid))),
				colorName, &tmpcolr);
		}
		colrs[i].red = tmpcolr.red;
		colrs[i].green = tmpcolr.green;
		colrs[i].blue = tmpcolr.blue;
		colrs[i].pixel = i;
		colrs[i].flags = DoRed|DoGreen|DoBlue;
	}
	for (i=Colors; i<256; i++)
	{
		colrs[i].red = 0;
		colrs[i].green = 0;
		colrs[i].blue = 0;
		colrs[i].pixel = i;
		colrs[i].flags = DoRed|DoGreen|DoBlue;
	}

	pixels = attrib.pixelindex;
	pix_data = (unsigned char *)malloc((*w) * (*h));
        if (pix_data == NULL)
        {
                fprintf(stderr, "Not enough memory for data.\n");
		xpmFreeInternAttrib(&attrib);
		xpmDataClose(&mdata);
                return((unsigned char *)NULL);
        }
	bptr = pix_data;
        for (i=0; i<((*w) * (*h)); i++)
        {
		int pix;

		pix = (int)*pixels;
                if (pix > (256 - 1))
                        pix = 0;
		*bptr++ = (unsigned char)pix;
                pixels++;
        }

	xpmFreeInternAttrib(&attrib);
	xpmDataClose(&mdata);

#ifdef TIMING
gettimeofday(&Tv, &Tz);
fprintf(stderr, "ReadXpm3Pixmap exit (%d.%d)\n", Tv.tv_sec, Tv.tv_usec);
#endif
        return(pix_data);
}


/* 
 * ******* end required file <xpmread.inc> *******
 */
 XrmQuark qimageList;
/* 
 * ******* begin required file <htmlw.inc> *******
 */
/* make emcas happy -*-C-*-  make emacs happy */
#undef IMAGECACHETRACE
/* 
   Copyright for the image resolving functions as well as for all of
   the html widget is the following (With kind permission of Mark
   Andreessen from the NCSA). We use the contents of img.c and picread.c:
 */

/****************************************************************************
 * NCSA Mosaic for the X Window System                                      *
 * Software Development Group                                               *
 * National Center for Supercomputing Applications                          *
 * University of Illinois at Urbana-Champaign                               *
 * 605 E. Springfield, Champaign IL 61820                                   *
 * mosaic@ncsa.uiuc.edu                                                     *
 *                                                                          *
 * Copyright (C) 1993, Board of Trustees of the University of Illinois      *
 *                                                                          *
 * NCSA Mosaic software, both binary and source (hereafter, Software) is    *
 * copyrighted by The Board of Trustees of the University of Illinois       *
 * (UI), and ownership remains with the UI.                                 *
 *                                                                          *
 * The UI grants you (hereafter, Licensee) a license to use the Software    *
 * for academic, research and internal business purposes only, without a    *
 * fee.  Licensee may distribute the binary and source code (if released)   *
 * to third parties provided that the copyright notice and this statement   *
 * appears on all copies and that no charge is associated with such         *
 * copies.                                                                  *
 *                                                                          *
 * Licensee may make derivative works.  However, if Licensee distributes    *
 * any derivative work based on or derived from the Software, then          *
 * Licensee will (1) notify NCSA regarding its distribution of the          *
 * derivative work, and (2) clearly notify users that such derivative       *
 * work is a modified version and not the original NCSA Mosaic              *
 * distributed by the UI.                                                   *
 *                                                                          *
 * Any Licensee wishing to make commercial use of the Software should       *
 * contact the UI, c/o NCSA, to negotiate an appropriate license for such   *
 * commercial use.  Commercial use includes (1) integration of all or       *
 * part of the source code into a product for sale or license by or on      *
 * behalf of Licensee to third parties, or (2) distribution of the binary   *
 * code or source code to third parties that need it to utilize a           *
 * commercial product sold or licensed by or on behalf of Licensee.         *
 *                                                                          *
 * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR   *
 * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED          *
 * WARRANTY.  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE    *
 * USERS OF THIS SOFTWARE.                                                  *
 *                                                                          *
 * By using or copying this Software, Licensee agrees to abide by the       *
 * copyright law and all other applicable laws of the U.S. including, but   *
 * not limited to, export control laws, and the terms of this license.      *
 * UI shall have the right to terminate this license immediately by         *
 * written notice upon Licensee's breach of, or non-compliance with, any    *
 * of its terms.  Licensee may be held legally responsible for any          *
 * copyright infringement that is caused or encouraged by Licensee's        *
 * failure to abide by the terms of this license.                           *
 *                                                                          *
 * Comments and questions are welcome and can be sent to                    *
 * mosaic-x@ncsa.uiuc.edu.                                                  *
 ****************************************************************************/

#define HIGHWATERIMAGESIZE 300000

#include <values.h>
#include <HTMLP.h>
#include <ctype.h>

typedef struct ele_rec  HTMLElementRecord;

#define DEF_BLACK       BlackPixel(dsp, DefaultScreen(dsp))
#define DEF_WHITE       WhitePixel(dsp, DefaultScreen(dsp))
/*#define	MAX_LINE	81*/
#define	MAX_LINE	256
#define NO_VISUAL       200


unsigned long fg_pixel, bg_pixel;
XColor fg_color, bg_color;

char nibMask[8] = {
	1, 2, 4, 8, 16, 32, 64, 128
};


/* Caching Mechanism is a must, since Conversion Procedure is called
   for each resize (and we use opaqueResize ....)
   
 */

typedef struct _imgDataRec
    {
    XrmQuark              qFilename;
    int                   count;
    ImageInfo             *imgData;    
    long                  size;
    struct _imgDataRec    *next;
    } imgDataRec, *imgDataRecPtr;

typedef struct _htmlImgCache 
    {
    imgDataRecPtr         dataRec;
    struct _htmlImgCache  *next;
    } htmlImgCacheStruct, *htmlImgCachePtr;

imgDataRecPtr     imgList  = NULL;



#ifdef IMAGECACHETRACE
void
printWidgetInfo(text,w,ptr)
char   *text;
Widget w;
htmlImgCachePtr ptr;
    {
    fprintf(stderr, "----%s(%p)--%s--WidgetInfo Ptr: %p------------\n", 
	    XtName(w), w, text, ptr);
    
    while(ptr)
	{
	fprintf(stderr, "   Data %p contains filename %s, count %d (next %p)\n",
		ptr, XrmQuarkToString(ptr->dataRec->qFilename),
		ptr->dataRec->count, ptr->next);
	ptr=ptr->next;
	}
    }

void
printCacheInfo(text)
char *text;
    {
    imgDataRecPtr ptr = imgList;
    
    fprintf(stderr, "****%s*****CacheInfo ImgList: %p------------\n", text, ptr);

    while(ptr)
	{
	fprintf(stderr, "   Data %p contains filename %s, count %d (next %p)\n",
		ptr, XrmQuarkToString(ptr->qFilename),
		ptr->count, ptr->next);
	ptr=ptr->next;
	}
    }
#endif


/* Add imgData to global list and return address.
 * Does NOT check wether imgData is allready in the list 
 */

imgDataRecPtr 
htmlAddImgData(qFilename, imgData)
XrmQuark   qFilename;
ImageInfo  *imgData;
    {
    imgDataRecPtr    ptr;

    DBUG_ENTER("htmlAddImgData");

    ptr = (imgDataRecPtr)XtMalloc(sizeof(imgDataRec));
    ptr->next = imgList;
    ptr->qFilename = qFilename;
    ptr->count = 0;
    ptr->imgData = imgData;
    ptr->size = imgData->num_colors * 3 * sizeof(int) + 
	        imgData->width * imgData->height;
    imgList = ptr;

#ifdef IMAGECACHETRACE
    printCacheInfo("Nach AddImgData");
#endif
    DBUG_RETURN(ptr);
    } 


/* actually free colors and image data */

void
free_image_data (img)
ImageInfo *img;
    {
    if (!img)
	return;

    if (img->reds)
      {
	free (img->reds);
	img->reds = NULL;
      }
    if (img->greens)
      {
	free (img->greens);
	img->greens = NULL;
      }
    if (img->blues)
      {
	free (img->blues);
	img->blues = NULL;
      }
    if (img->image_data)
      {
	free (img->image_data);
	img->image_data = NULL;
      }

    return;
    }


/* 
 * Search all available imgData Structures for
 * matching entry, return NULL if not found, the data 
 * structure otherwise.
 */



imgDataRecPtr
htmlLocateImgInfo(qFilename)
XrmQuark   qFilename;
    {
    imgDataRecPtr    ptr, *reference;
    long             memUsed;

    DBUG_ENTER("htmlLocateImgInfo");

#ifdef IMAGECACHETRACE
    printCacheInfo("Vor Locate");
    fprintf(stderr,"   looking for %s\n",XrmQuarkToString(qFilename));
#endif

    for (ptr = imgList, memUsed = 0; 
	 ((ptr != NULL) && (ptr->qFilename != qFilename));
	 ptr = ptr->next)
	memUsed += ptr->size;

    if (ptr)
	DBUG_RETURN(ptr);

    /* fprintf(stderr,"memused=%ld\n",memUsed); */

    if (memUsed > HIGHWATERIMAGESIZE)
	{
	for (reference = &imgList, ptr = imgList; 
	     ptr != NULL; 
	     reference = &ptr)
	    {
	    if (ptr->count == 0)
		{
		/*
		fprintf(stderr,"freeing ptr=%p, name=%s, count=%d\n",
			ptr,XrmQuarkToString(ptr->qFilename),ptr->count);
		*/

		free_image_data(ptr->imgData);
		memUsed -= ptr->size;

		*reference = ptr->next;
		XtFree((char*)ptr);
		/* fprintf(stderr,"after XtFree, memUsed=%d\n",memUsed); */
		ptr = *reference;
		}
	    else
		ptr = ptr->next;
	    }
	}
#ifdef IMAGECACHETRACE
    printCacheInfo("Nach Loesch");
#endif
    DBUG_RETURN(NULL);
    }

/* This function is called by the MM* routines and frees 
 * the reference list of a widget. The imageInfo is NOT freed, we'll
 * only decrement the counter;
 */

void
freeImageData(ptr)
char *ptr;
    {
    htmlImgCachePtr iPtr = (htmlImgCachePtr) ptr;
    htmlImgCachePtr nextPtr;

    DBUG_ENTER("freeImageData");

    while (iPtr != NULL)
	{
	nextPtr = iPtr->next;
	iPtr->dataRec->count--;
	XtFree((char *)iPtr);
	iPtr = nextPtr;
	}
    DBUG_VOID_RETURN;
    }




/*
 * Add a new ref to a widget's image-list if not yet there
 */

void
htmlAddRefToWidget(w, qFilename, dataPtr)
Widget          w;
XrmQuark        qFilename;
imgDataRecPtr   dataPtr;
    {
    MMattribListPtr     *al = MMgetAttribList(w,True);
    htmlImgCachePtr     imgCachePtr = (htmlImgCachePtr)MMgetValue(al, qimageList);
    htmlImgCachePtr     iPtr;
    
    DBUG_ENTER("htmlAddRefToWidgetCache");

#ifdef IMAGECACHETRACE    
    printWidgetInfo("Beginn:", w, imgCachePtr);
#endif

    if (!imgCachePtr) 
	{  /* First image ref for this widget */
	imgCachePtr = (htmlImgCachePtr) XtMalloc(sizeof(htmlImgCacheStruct));
	imgCachePtr->next = NULL;
	dataPtr->count++;
/*
 	fprintf(stderr, "Ptr: %p; Incrementing count for %s to %d\n",
		imgCachePtr,
		XrmQuarkToString(qFilename), dataPtr->count);
*/
	imgCachePtr->dataRec = dataPtr;
	MMreplace(al, qimageList, (char *) imgCachePtr, freeImageData);
	}
    else
	{ /* scan existing image refs */

	for (iPtr = imgCachePtr;
	     ((iPtr->next != NULL) && (iPtr->dataRec->qFilename != qFilename));
	     iPtr = iPtr->next);
	
	if (iPtr->dataRec->qFilename != qFilename)
	    { /* first display of this image for widget: add image ref */
	    iPtr->next = (htmlImgCachePtr) XtMalloc(sizeof(htmlImgCacheStruct));
	    iPtr = iPtr->next;
	    dataPtr->count++;
/*
	    fprintf(stderr, "New href: Incrementing count for %s to %d\n", 
		    XrmQuarkToString(qFilename), dataPtr->count);
*/

	    iPtr->dataRec = dataPtr;
	    iPtr->next = NULL;
	    }
	}

#ifdef IMAGECACHETRACE    
    printWidgetInfo("End: ", w, imgCachePtr);
#endif
    
    DBUG_VOID_RETURN;
    }
    

/* this function is essentially from NCSA Mosaic */

unsigned char *ReadXpmPixmap(view, fp, datafile, w, h, colrs, Colors, CharsPP)
Widget view;
FILE *fp;
char *datafile;
int *w, *h;
XColor *colrs;
int Colors, CharsPP;
{
	unsigned char *pixels;
	char **Color_Vals;
	XColor tmpcolr;
	int i, j, k;
	int found;
	char line[BUFSIZ], name_and_type[MAX_LINE];
	unsigned char *dataP;
	unsigned char *bitp;
	int tchar;
	char *t;
	char *t2;
	Display *dsp = XtDisplay(view);

	if (Colors == 0)
	{
		/* fprintf(stderr, "Can't find Colors.\n"); */
		return((unsigned char *)NULL);
	}
	if (*w == 0)
	{
		/* fprintf(stderr, "Can't read image.\n"); */
		return((unsigned char *)NULL);
	}
	if (*h == 0)
	{
		/* fprintf(stderr, "Can't read image.\n"); */
		return((unsigned char *)NULL);
	}

	Color_Vals = (char **)XtMalloc(sizeof(char *) * Colors);
	for (i=0; i<Colors; i++)
	{
		tchar = getc(fp);
		while ((tchar != '"')&&(tchar != EOF))
		{
			tchar = getc(fp);
		}
		Color_Vals[i] = (char *)XtMalloc(sizeof(char) * (CharsPP + 1));
		j = 0;
		tchar = getc(fp);
		while ((tchar != '"')&&(tchar != EOF)&&(j < CharsPP))
		{
			Color_Vals[i][j] = (char)tchar;
			tchar = getc(fp);
			j++;
		}
		Color_Vals[i][j] = '\0';
		if (tchar != '"')
		{
			tchar = getc(fp);
			while ((tchar != '"')&&(tchar != EOF))
			{
				tchar = getc(fp);
			}
		}
		tchar = getc(fp);
		while ((tchar != '"')&&(tchar != EOF))
		{
			tchar = getc(fp);
		}
		j = 0;
		tchar = getc(fp);
		while ((tchar != '"')&&(tchar != EOF))
		{
			line[j] = (char)tchar;
			tchar = getc(fp);
			j++;
		}
		line[j] = '\0';
		XParseColor(dsp, DefaultColormap(dsp, DefaultScreen(dsp)),
			line, &tmpcolr);
		colrs[i].red = tmpcolr.red;
		colrs[i].green = tmpcolr.green;
		colrs[i].blue = tmpcolr.blue;
		colrs[i].pixel = i;
		colrs[i].flags = DoRed|DoGreen|DoBlue;
	}
	for (i=Colors; i<256; i++)
	{
		colrs[i].red = 0;
		colrs[i].green = 0;
		colrs[i].blue = 0;
		colrs[i].pixel = i;
		colrs[i].flags = DoRed|DoGreen|DoBlue;
	}
	tchar = getc(fp);
	while ((tchar != ';')&&(tchar != EOF))
	{
		tchar = getc(fp);
	}

	for ( ; ; )
	{
		if (!(fgets(line, MAX_LINE, fp)))
		{
			fprintf(stderr, "Can't find Pixels\n");
			return((unsigned char *)NULL);
		}
		else if (sscanf(line,"static char * %s = {",name_and_type) == 1)
		{
			if ((t = strrchr(name_and_type, '_')) == NULL)
			{
				t = name_and_type;
			}
			else
			{
				t++;
			}
			if ((t2 = strchr(name_and_type, '[')) != NULL)
			{
				*t2 = '\0';
			}
			if (!strcmp("pixels", t))
			{
				break;
			}
		}
	}
	pixels = (unsigned char *)XtMalloc((*w) * (*h));
	if (pixels == NULL)
	{
		fprintf(stderr, "Not enough memory for data.\n");
		return((unsigned char *)NULL);
	}

	line[0] = '\0';
	t = line;
	dataP = pixels;
	tchar = getc(fp);
	while ((tchar != '"')&&(tchar != EOF))
	{
		tchar = getc(fp);
	}
	tchar = getc(fp);
	for (j=0; j<(*h); j++)
	{
		for (i=0; i<(*w); i++)
		{
			k = 0;
			while ((tchar != '"')&&(tchar != EOF)&&(k < CharsPP))
			{
				line[k] = (char)tchar;
				tchar = getc(fp);
				k++;
			}
			if ((k == 0)&&(tchar == '"'))
			{
				tchar = getc(fp);
				while ((tchar != '"')&&(tchar != EOF))
				{
					tchar = getc(fp);
				}
				k = 0;
				tchar = getc(fp);
				while ((tchar != '"')&&(tchar != EOF)&&
					(k < CharsPP))
				{
					line[k] = (char)tchar;
					tchar = getc(fp);
					k++;
				}
			}
			line[k] = '\0';
			found = 0;
			for (k=0; k<Colors; k++)
			{
				if (strncmp(Color_Vals[k], line, CharsPP) == 0)
				{
					*dataP++ = (unsigned char)k;
					found = 1;
					break;
				}
			}
			if (found == 0)
			{
				fprintf(stderr, "Invalid Pixel (%2s) in file %s\n", line, datafile);
				*dataP++ = (unsigned char)0;
			}
		}
	}

	bitp = pixels;
	for (i=0; i<((*w) * (*h)); i++)
	{
		if ((int)*bitp > (256 - 1))
			*bitp = (unsigned char)0;
		bitp++;
	}

	for (i=0; i<Colors; i++)
	{
		XtFree((char *)Color_Vals[i]);
	}
	XtFree((char *)Color_Vals);
	return(pixels);
}

/* This function is essentially from NCSA Mosaic */

unsigned char *ReadXbmBitmap(view, fp, datafile, w, h, colrs)
Widget view;
FILE *fp;
char *datafile;
int *w, *h;
XColor *colrs;
{
	char line[MAX_LINE], name_and_type[MAX_LINE];
	char *t;
	char *t2;
	unsigned char *ptr, *dataP;
	int bytes_per_line, version10p, raster_length, padding;
	int i, bytes, temp, value;
	int Ncolors, charspp, xpmformat;
        static unsigned long fg_pixel, bg_pixel;
        static int done_fetch_colors = 0;
        extern XColor fg_color, bg_color;
	int blackbit;
	int whitebit;

        if (!done_fetch_colors)
	    {
             /* First, go fetch the pixels. */
#ifndef MOTIF11	    
	    XtVaGetValues (view, 
			   XtNforeground, &fg_pixel,
			   XtNbackground, &bg_pixel, 
			   NULL);
#else
	    XtVaGetValues (view, 
			   XtNbackground, &bg_pixel, 
			   NULL);
	    XtVaGetValues (XtParent(view),
			   XtNforeground, &fg_pixel,
			   NULL);
#endif
             
	    /* Now, load up fg_color and bg_color. */
	    fg_color.pixel = fg_pixel;
	    bg_color.pixel = bg_pixel;
	    
	    /* Now query for the full color info. */
	    XQueryColor(XtDisplay (view), 
			DefaultColormap (XtDisplay (view),
					 DefaultScreen (XtDisplay (view))),
			&fg_color);
             XQueryColor(XtDisplay (view), 
			 DefaultColormap (XtDisplay (view),
					  DefaultScreen (XtDisplay (view))),
			 &bg_color);
 
	    done_fetch_colors = 1;

#ifdef MORETHAN256COLORS
            /*
             * For a TrueColor visual, we can't use the pixel value as
             * the color index because it is > 255.  Arbitrarily assign
             * 0 to foreground, and 1 to background.
             */
            if (Vclass == TrueColor)
		{
                fg_color.pixel = 0;
		bg_color.pixel = 1;
                }
#endif
	    }

 /*
	if (Rdata.reverse_inlined_bitmap_colors)
	    {
	    blackbit = bg_color.pixel;
	    whitebit = fg_color.pixel;
	    }
	else
*/
	    {
	    blackbit = fg_color.pixel;
	    whitebit = bg_color.pixel;
	    }

	/*
	 * Error out here on visuals we can't handle so we won't core dump
	 * later.
	
	if (((blackbit > 255)||(whitebit > 255))&&(Vclass != TrueColor))
	  {
		fprintf(stderr, "Error:  cannot deal with default colormap that is deeper than 8, and not TrueColor\n");
                fprintf(stderr, "        If you actually have such a system, please notify mosaic-x@ncsa.uiuc.edu.\n");
                fprintf(stderr, "        We thank you for your support.\n");
		exit(1);
	  }
*/
/*        if (Rdata.reverse_inlined_bitmap_colors)
          {
            colrs[blackbit].red = bg_color.red;
            colrs[blackbit].green = bg_color.green;
            colrs[blackbit].blue = bg_color.blue;
            colrs[blackbit].pixel = bg_color.pixel;
            colrs[blackbit].flags = DoRed|DoGreen|DoBlue;
            
            colrs[whitebit].red = fg_color.red;
            colrs[whitebit].green = fg_color.green;
            colrs[whitebit].blue = fg_color.blue;
            colrs[whitebit].pixel = fg_color.pixel;
            colrs[whitebit].flags = DoRed|DoGreen|DoBlue;
          }
        else
          { */
            colrs[blackbit].red = fg_color.red;
            colrs[blackbit].green = fg_color.green;
            colrs[blackbit].blue = fg_color.blue;
            colrs[blackbit].pixel = fg_color.pixel;
            colrs[blackbit].flags = DoRed|DoGreen|DoBlue;
            
            colrs[whitebit].red = bg_color.red;
            colrs[whitebit].green = bg_color.green;
            colrs[whitebit].blue = bg_color.blue;
            colrs[whitebit].pixel = bg_color.pixel;
            colrs[whitebit].flags = DoRed|DoGreen|DoBlue;

	*w = 0;
	*h = 0;
	Ncolors = 0;
	charspp = 0;
	xpmformat = 0;
	for ( ; ; )
	{
		if (!(fgets(line, MAX_LINE, fp)))
			break;
		if (strlen(line) == (MAX_LINE - 1))
		{
#ifdef DEBUG
			fprintf(stderr, "Line too long.\n");
#endif
			return((unsigned char *)NULL);
		}
		if (sscanf(line, "#define %s %d", name_and_type, &value) == 2)
		{
			if (!(t = strrchr(name_and_type, '_')))
				t = name_and_type;
			else
				t++;
			if (!strcmp("width", t))
				*w= value;
			if (!strcmp("height", t))
				*h= value;
			if (!strcmp("ncolors", t))
				Ncolors = value;
			if (!strcmp("pixel", t))
				charspp = value;
			continue;
		}
		if (sscanf(line, "static short %s = {", name_and_type) == 1)
		{
			version10p = 1;
			break;
		}
		else if 
		  (sscanf(line,"static char * %s = {",name_and_type) == 1 || 
		   sscanf(line,"static unsigned char * %s = {",name_and_type) == 1 )
		{
			xpmformat = 1;
			if (!(t = strrchr(name_and_type, '_')))
				t = name_and_type;
			else
				t++;
			if ((t2 = strchr(name_and_type, '[')) != NULL)
				*t2 = '\0';
			if (!strcmp("mono", t))
				continue;
			else
				break;
		}
		else if 
		  (sscanf(line, "static char %s = {", name_and_type) == 1 ||
		   sscanf(line, "static unsigned char %s = {", name_and_type) == 1)
		{
			version10p = 0;
			break;
		}
		else
			continue;
	}
	if (xpmformat)
	{
		dataP = ReadXpmPixmap(view, fp, datafile, w, h, colrs, Ncolors, charspp);
		return(dataP);
	}
	if (*w == 0)
	{
		/* fprintf(stderr, "Can't read image.\n"); */
		return((unsigned char *)NULL);
	}
	if (*h == 0)
	{
		/* fprintf(stderr, "Can't read image.\n"); */
		return((unsigned char *)NULL);
	}
	padding = 0;
	if (((*w % 16) >= 1)&&((*w % 16) <= 8)&&version10p)
	{
		padding = 1;
	}
	bytes_per_line = ((*w + 7) / 8) + padding;
	raster_length =  bytes_per_line * *h;
	dataP = (unsigned char *)XtMalloc((*w) * (*h));
	if (dataP == NULL)
	{
		fprintf(stderr, "Not enough memory.\n");
		return((unsigned char *)NULL);
	}
	ptr = dataP;
	if (version10p)
	{
		int cnt = 0;
		int lim = (bytes_per_line - padding) * 8;
		for (bytes = 0; bytes < raster_length; bytes += 2)
		{
			if (fscanf(fp, " 0x%x%*[,}]%*[ \r\n]", &value) != 1)
			{
				fprintf(stderr, "Error scanning bits item.\n");
				return((unsigned char *)NULL);
			}
			temp = value;
			value = temp & 0xff;
			for (i = 0; i < 8; i++)
			{
				if (cnt < (*w))
				{
					if (value & nibMask[i])
						*ptr++ = blackbit;
					else
						*ptr++ = whitebit;
				}
				if (++cnt >= lim)
					cnt = 0;
			}
			if ((!padding)||((bytes+2) % bytes_per_line))
			{
				value = temp >> 8;
				for (i = 0; i < 8; i++)
				{
					if (cnt < (*w))
					{
						if (value & nibMask[i])
							*ptr++ = blackbit;
						else
							*ptr++ = whitebit;
					}
					if (++cnt >= lim)
						cnt = 0;
				}
			}
		}
	}
	else
	{
		int cnt = 0;
		int lim = bytes_per_line * 8;
		for (bytes = 0; bytes < raster_length; bytes++)
		{
			if (fscanf(fp, " 0x%x%*[,}]%*[ \r\n]", &value) != 1)
			{
				fprintf(stderr, "Error scanning bits item.\n");
				return((unsigned char *)NULL);
			}
			for (i = 0; i < 8; i++)
			{
				if (cnt < (*w))
				{
					if (value & nibMask[i])
						*ptr++ = blackbit;
					else
						*ptr++ = whitebit;
				}
				if (++cnt >= lim)
					cnt = 0;
			}
		}
	}
	return(dataP);
}

unsigned char *ReadBitmap(html, datafile, w, h, colrs, bg)
Widget html;
char *datafile;
int *w, *h;
XColor *colrs;
int *bg;
{
	unsigned char *bit_data;
	FILE *fp;

	*bg = -1;

        fp = fopen(datafile, "r");
	if (fp != NULL)
	{
	/* First, go fetch foreground and background colors */
	XtVaGetValues (html, XtNforeground, &fg_pixel,
		       XtNbackground, &bg_pixel, NULL);

	/* Now, load up fg_color and bg_color. */
	fg_color.pixel = fg_pixel;
	bg_color.pixel = bg_pixel;
            
	/* Now query for the full color info. */
	XQueryColor 
	    (XtDisplay (html), 
	     DefaultColormap (XtDisplay (html),
			      DefaultScreen (XtDisplay (html))),
	                      &fg_color);

	XQueryColor 
	    (XtDisplay (html), 
	     DefaultColormap (XtDisplay (html),
			      DefaultScreen (XtDisplay (html))),
	                      &bg_color);

	bit_data = ReadGIF(fp, w, h, colrs);
	if (bit_data != NULL)
	    {
	    if (fp != stdin) fclose(fp);
	    return(bit_data);
	    }
	rewind(fp);

	bit_data = ReadXbmBitmap(html,fp, datafile, w, h, colrs);
	if (bit_data != NULL)
	    {
	    if (fp != stdin) fclose(fp);
	    return(bit_data);
	    }
	rewind(fp);
	
	bit_data = ReadXpm3Pixmap(html,fp, datafile, w, h, colrs, bg);
	if (bit_data != NULL)
	    {
	    if (fp != stdin) fclose(fp);
	    return(bit_data);
	    }
	}
	if (fp != stdin) fclose(fp);
	return((unsigned char *)NULL);
}

/* Image resolution function. in wide parts from NCSA Mosaic, cache is ours */
static ImageInfo *Resolve (w, src, noload)
Widget w;
char *src;
int noload;
{
  int i, cnt;
  unsigned char *data;
  unsigned char *bg_map;
  unsigned char *bgptr;
  unsigned char *ptr;
  int width, height;
  int widthbyheight = 0;
  int Used[256];
  XColor colrs[256];
  ImageInfo *img_data;
  int bg, bg_red, bg_green, bg_blue;
#ifdef MORETHAN256COLORS
  extern int Vclass;
#endif
  XrmQuark   qFilename;
  char    *origSrc = src;
  imgDataRecPtr  dataPtr;

  DBUG_ENTER("Resolve");

  if (!src)
    DBUG_RETURN(NULL);

  /*
   * If we allready have this imgInfo in cache => just update the widget's 
   * image list and increment the reference counter....
   */ 

  qFilename = XrmStringToQuark(src);
  if ((dataPtr = htmlLocateImgInfo(qFilename)) != NULL)
	{
	htmlAddRefToWidget(w, qFilename, dataPtr);
	DBUG_RETURN(dataPtr->imgData);
	}

  src = XtResolvePathname(XtDisplay(w), "bitmaps", origSrc, "", 
			  wafeFileSearchPath, NULL, 0, NULL);
  
  if (src == NULL)
        DBUG_RETURN(NULL);

  /* If we don't have the image cached and noload is high,
     then just return NULL to avoid doing a network load. */
  /* Also return if interrupted is high. */
  if (noload /*|| interrupted*/)
    {
      XtFree (src);
      DBUG_RETURN(NULL);
    }

  /*
   * No transparent background by default
   */
  bg = -1;
  bg_map = NULL;
    {
      /* We have to load the image. */
      
      data = ReadBitmap(w, src, &width, &height, colrs, &bg);
      XtFree (src);
      /* if we have a transparent background, prepare for it */
      if ((bg >= 0)&&(data != NULL))
      {
        bg_red = colrs[bg].red;
        bg_green = colrs[bg].green;
        bg_blue = colrs[bg].blue;
        bg_map = (unsigned char *)malloc(width * height);
      }
      
      if (data == NULL)
            DBUG_RETURN(NULL);
      
      img_data = (ImageInfo *)malloc(sizeof(ImageInfo));
      img_data->width = width;
      img_data->height = height;
      img_data->image_data = data;
      img_data->image = (Pixmap)NULL;
      /* Bandaid for bug afflicting Eric's code, apparently. */
      img_data->internal = 0;
    }

  widthbyheight = img_data->width * img_data->height;

  /* Fill out used array. */
  for (i=0; i < 256; i++)
    {
      Used[i] = 0;
    }
  cnt = 1;
  bgptr = bg_map;
  ptr = img_data->image_data;
  for (i=0; i < widthbyheight; i++)
    {
      if (Used[(int)*ptr] == 0)
        {
          Used[(int)*ptr] = cnt;
          cnt++;
        }
      if (bg >= 0)
        {
                if (*ptr == bg)
                {
                        *bgptr = (unsigned char)1;
                }
                else
                {
                        *bgptr = (unsigned char)0;
                }
                bgptr++;
        }
      ptr++;
    }
  cnt--;
#ifdef MORETHAN256COLORS  
  /*
   * If the image has too many colors, apply a median cut algorithm to
   * reduce the color usage, and then reprocess it.
   * Don't cut colors for direct mapped visuals like TrueColor.
   */
  if ((cnt > Rdata.colors_per_inlined_image)&&(Vclass != TrueColor))
    {
      MedianCut(img_data->image_data, &img_data->width, 
                &img_data->height, colrs, cnt, 
                Rdata.colors_per_inlined_image);
      
      for (i=0; i < 256; i++)
        Used[i] = 0;
      cnt = 1;
      ptr = img_data->image_data;
      for (i=0; i < widthbyheight; i++)
        {
          if (Used[(int)*ptr] == 0)
            {
              Used[(int)*ptr] = cnt;
              cnt++;
            }
          ptr++;
        }
      cnt--;

      /* if we had a transparent bg, MedianCut used it.  Get a new one */
      if (bg >= 0)
      {
        cnt++;
        bg = 256;
      }
    }
#endif

  img_data->num_colors = cnt;
    {
      img_data->reds = (int *)malloc(sizeof(int) * cnt);
      img_data->greens = (int *)malloc(sizeof(int) * cnt);
      img_data->blues = (int *)malloc(sizeof(int) * cnt);
    }

  for (i=0; i < 256; i++)
    {
      int indx;
      
      if (Used[i] != 0)
        {
          indx = Used[i] - 1;
          img_data->reds[indx] = colrs[i].red;
          img_data->greens[indx] = colrs[i].green;
          img_data->blues[indx] = colrs[i].blue;
          /* squeegee in the background color */
          if ((bg >= 0)&&(i == bg))
          {
                img_data->reds[indx] = bg_red;
                img_data->greens[indx] = bg_green;
                img_data->blues[indx] = bg_blue;
          }
        }
    }
#ifdef MORETHAN256COLORS  
    /* if MedianCut ate our background, add the new one now. */
    if (bg == 256)
    {
        img_data->reds[cnt - 1] = bg_red;
        img_data->greens[cnt - 1] = bg_green;
        img_data->blues[cnt - 1] = bg_blue;
    }
#endif
  bgptr = bg_map;
  ptr = img_data->image_data;
  for (i=0; i < widthbyheight; i++)
    {
      *ptr = (unsigned char)(Used[(int)*ptr] - 1);
      /* if MedianCut ate the background, enforce it here */
      if (bg == 256)
      {
        if ((int)*bgptr == 1)
        {
                *ptr = (unsigned char)(cnt - 1);
        }
        bgptr++;
      }
      ptr++;
    }

  /* free the background map if we have one */
  if (bg_map != NULL)
  {
    free(bg_map);
  }
  
  dataPtr = htmlAddImgData(qFilename, img_data);
  htmlAddRefToWidget(w, qFilename, dataPtr);  

  DBUG_RETURN(img_data);
}


int
visitedTestHandler(w, href)
Widget w;
char   *href;
    {
    extern char *tclHandlers[];
    DBUG_ENTER("visitedTestHandler");

    if(tclHandlers[HTMLVISITED])
	{
	int result;

	Tcl_SetVar(wafeInterpreter, "HTMLWIDGET", XtName(w), TCL_GLOBAL_ONLY);
	Tcl_SetVar(wafeInterpreter, "HTMLHREF", href, TCL_GLOBAL_ONLY);
	(void) wafeEval(wafeInterpreter, tclHandlers[HTMLVISITED], "HTMLVISITED");
	
	if (sscanf(wafeInterpreter->result, "%d", &result) != 1)
	    {
	    fprintf(stderr, 
	    "HTMLVISITED Handler Warning: Procedure should return 0 or 1, assuming 0\n");
	    result = 0;
	    }
	DBUG_RETURN(result);
	}
    else
	{
/*	fprintf(stderr, "No handler registered...\n");*/
	DBUG_RETURN(0);
	}
    
    }



Widget
crtHtmlWidget(father, name, args, numArgs)
Widget   father;
char     *name;
ArgList  args;
Cardinal numArgs;
    {
    Widget             new;
    Arg                arg[2];

    /* registering resolveImageFunction before user can use a picture */
    XtSetArg(arg[0], WbNresolveImageFunction, Resolve);
    XtSetArg(arg[1], WbNpreviouslyVisitedTestFunction, visitedTestHandler);

    new = XtCreateWidget(name, htmlWidgetClass, father, arg, 2);

    XtSetValues(new, args, numArgs);
    return(new);
    }


/*
 * Convenience function to return the position of the element
 * based on the element id passed in.
 * Function returns the page number and fills in x,y pixel values.
 * If there is no such element, 0,0 of page 1 is returned.
 */
Boolean
#ifdef _NO_PROTO
HTMLIdToElement(w, element_id, returnRec)
	Widget w;
	int element_id;
        HTMLElementRecord ** returnRec;
#else
HTMLIdToElement(Widget w, int element_id, HTMLElementRecord ** returnRec)
#endif
    {
    HTMLWidget hw = (HTMLWidget)w;
    struct ele_rec *start;
    struct ele_rec *eptr;
    
    eptr = NULL;
    start = hw->html.formatted_elements;
	
    while (start != NULL)
	{
	fprintf(stderr,"HTMLIdToElement: comparing %d with %d\n", 
		start->ele_id, element_id);
	if (start->ele_id == element_id)
	    {
	    *returnRec = start;
	    return True;
	    }
	start = start->next;
	}
    return False;
    }

void
#ifdef _NO_PROTO
HTMLsetElementBg(w, element_id, colorString)
	Widget w;
	int element_id;
        char * colorString;
#else
HTMLsetElementBg(Widget w, int element_id, char * colorString)
#endif
    { 
    HTMLElementRecord *returnRec;    
    Boolean validId = HTMLIdToElement(w, element_id, &returnRec);
    fprintf(stderr,"HTMLsetElementBg: id: %d is a validId = %d\n", element_id,
	    (int) validId);
    
    if (validId)
	{
	XrmValue input,output;

	input.addr = colorString;
	input.size = strlen(colorString)+1;
	output.addr =  NULL;

	XtConvert(w, "String", &input, "Pixel", &output);
	if (output.addr)
	    {
	    fprintf(stderr,"background pixel was %p\n", returnRec->bg);
	    returnRec->bg = *(Pixel *) output.addr;
	    fprintf(stderr,"background pixel is  %p\n", returnRec->bg);
	    RefreshTextRange(w,returnRec,returnRec);
	    }
	}
    }


String
hTMLGetHRefs(w) 
Widget w;
    {
    int num;
    char **p = HTMLGetHRefs((w),&num);
    fprintf(stderr, "returned from get hrefs, num=%d\n",num);
    return Tcl_Merge(num,p);
    }



/* 
 * ******* end required file <htmlw.inc> *******
 */
#include <HTML.h>
/* 
 * String
 * HTMLGetText
 * 	in: HTMLWidget     # HTML Widget
 * 	in: int            # Pretty Code 0-2
 */

int 
com_HTMLGetText(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar2;
     String returnVar;

     DBUG_ENTER("HTMLGetText");  

     if (argc != 3) 
	 {
	 argcError("HTMLGetText","",2,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLGetText","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[2], "%d", &localVar2)))
          {
          convError("HTMLGetText","2",argv[2],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     returnVar = HTMLGetText(localVar1,localVar2);

     
     Tcl_SetResult(comInterpreter, returnVar, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * String
 * HTMLGetTextAndSelection
 * 	in: HTMLWidget    # HTML Widget
 * 	out: String       # Selection starts
 * 	out: String       # Selcetion ends
 * 	out: String       # Insertion Points
 */

int 
com_HTMLGetTextAndSelection(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     String localVar2;
     String localVar3;
     String localVar4;
     String returnVar;
     char conversionBuffer[100];

     DBUG_ENTER("HTMLGetTextAndSelection");  

     if (argc != 5) 
	 {
	 argcError("HTMLGetTextAndSelection","",4,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLGetTextAndSelection","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     returnVar = HTMLGetTextAndSelection(localVar1,&localVar2,&localVar3,&localVar4);

     
     Tcl_SetVar(wafeInterpreter, argv[2], localVar2, 0);

     
     Tcl_SetVar(wafeInterpreter, argv[3], localVar3, 0);

     
     Tcl_SetVar(wafeInterpreter, argv[4], localVar4, 0);

     
     Tcl_SetResult(comInterpreter, returnVar, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * String 
 * hTMLGetHRefs vulgo HTMLGetHRefs
 * 	in: HTMLWidget    # HTML Widget
 */

int 
com_HTMLGetHRefs(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     String returnVar;

     DBUG_ENTER("HTMLGetHRefs");  

     if (argc != 2) 
	 {
	 argcError("HTMLGetHRefs","",1,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLGetHRefs","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     returnVar = hTMLGetHRefs(localVar1);

     
     Tcl_SetResult(comInterpreter, returnVar, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * int
 * HTMLPositionToId
 * 	in: HTMLWidget    # HTML Widget
 * 	in: int           # x Coordinate
 * 	in: int           # y Coordinate
 */

int 
com_HTMLPositionToId(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar2;
     int localVar3;
     int returnVar;
     char conversionBuffer[100];

     DBUG_ENTER("HTMLPositionToId");  

     if (argc != 4) 
	 {
	 argcError("HTMLPositionToId","",3,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLPositionToId","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[2], "%d", &localVar2)))
          {
          convError("HTMLPositionToId","2",argv[2],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[3], "%d", &localVar3)))
          {
          convError("HTMLPositionToId","3",argv[3],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     returnVar = HTMLPositionToId(localVar1,localVar2,localVar3);

     sprintf(conversionBuffer, "%d", returnVar);
     Tcl_SetResult(comInterpreter, conversionBuffer, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * int 
 * HTMLIdToPosition
 * 	in: HTMLWidget     # HTML Widget
 * 	in: int	           # Element ID
 * 	out: int           # x Coordinate
 * 	out: int           # y Coordinate
 */

int 
com_HTMLIdToPosition(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar2;
     int localVar3;
     int localVar4;
     int returnVar;
     char conversionBuffer[100];

     DBUG_ENTER("HTMLIdToPosition");  

     if (argc != 5) 
	 {
	 argcError("HTMLIdToPosition","",4,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLIdToPosition","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[2], "%d", &localVar2)))
          {
          convError("HTMLIdToPosition","2",argv[2],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     returnVar = HTMLIdToPosition(localVar1,localVar2,&localVar3,&localVar4);

     sprintf(conversionBuffer, "%d", localVar3);
     Tcl_SetVar(wafeInterpreter, argv[3], conversionBuffer, 0);

     sprintf(conversionBuffer, "%d", localVar4);
     Tcl_SetVar(wafeInterpreter, argv[4], conversionBuffer, 0);

     sprintf(conversionBuffer, "%d", returnVar);
     Tcl_SetResult(comInterpreter, conversionBuffer, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * int 
 * HTMLAnchorToPosition
 * 	in: HTMLWidget     # HTML Widget
 * 	in: String         # Anchor's name
 * 	out: int           # x Coordinate
 * 	out: int           # y Coordinate
 */

int 
com_HTMLAnchorToPosition(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar3;
     int localVar4;
     int returnVar;
     char conversionBuffer[100];

     DBUG_ENTER("HTMLAnchorToPosition");  

     if (argc != 5) 
	 {
	 argcError("HTMLAnchorToPosition","",4,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLAnchorToPosition","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

    /* no need to assign  << localVar2 = argv[2] >>  */ 

     returnVar = HTMLAnchorToPosition(localVar1,argv[2],&localVar3,&localVar4);

     sprintf(conversionBuffer, "%d", localVar3);
     Tcl_SetVar(wafeInterpreter, argv[3], conversionBuffer, 0);

     sprintf(conversionBuffer, "%d", localVar4);
     Tcl_SetVar(wafeInterpreter, argv[4], conversionBuffer, 0);

     sprintf(conversionBuffer, "%d", returnVar);
     Tcl_SetResult(comInterpreter, conversionBuffer, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * void
 * HTMLClearSelection
 * 	in: HTMLWidget     # HTML Widget
 */

int 
com_HTMLClearSelection(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;

     DBUG_ENTER("HTMLClearSelection");  

     if (argc != 2) 
	 {
	 argcError("HTMLClearSelection","",1,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLClearSelection","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     HTMLClearSelection(localVar1);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * void 
 * HTMLSetSelection
 * 	in: HTMLWidget         # HTML Widget
 * 	in: ElementRef         # start
 * 	in: ElementRef	       # end
 */

int 
com_HTMLSetSelection(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     ElementRef localVar2;
     ElementRef localVar3;

     DBUG_ENTER("HTMLSetSelection");  

     if (argc != 4) 
	 {
	 argcError("HTMLSetSelection","",3,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLSetSelection","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     { char *charp;
         if (!(charp=Tcl_GetVar2(wafeInterpreter,argv[2],"id", 0)))
               {
               noVarCompError("HTMLSetSelection",argv[2],"id");
               DBUG_RETURN (TCL_ERROR);
               }
         if (!(sscanf(charp, "%d", &localVar2.id)))
              {
              convError("HTMLSetSelection","2.id",charp,"int");
              DBUG_RETURN (TCL_ERROR);
              }

         if (!(charp=Tcl_GetVar2(wafeInterpreter,argv[2],"pos", 0)))
               {
               noVarCompError("HTMLSetSelection",argv[2],"pos");
               DBUG_RETURN (TCL_ERROR);
               }
         if (!(sscanf(charp, "%d", &localVar2.pos)))
              {
              convError("HTMLSetSelection","2.pos",charp,"int");
              DBUG_RETURN (TCL_ERROR);
              }

     }

     { char *charp;
         if (!(charp=Tcl_GetVar2(wafeInterpreter,argv[3],"id", 0)))
               {
               noVarCompError("HTMLSetSelection",argv[3],"id");
               DBUG_RETURN (TCL_ERROR);
               }
         if (!(sscanf(charp, "%d", &localVar3.id)))
              {
              convError("HTMLSetSelection","3.id",charp,"int");
              DBUG_RETURN (TCL_ERROR);
              }

         if (!(charp=Tcl_GetVar2(wafeInterpreter,argv[3],"pos", 0)))
               {
               noVarCompError("HTMLSetSelection",argv[3],"pos");
               DBUG_RETURN (TCL_ERROR);
               }
         if (!(sscanf(charp, "%d", &localVar3.pos)))
              {
              convError("HTMLSetSelection","3.pos",charp,"int");
              DBUG_RETURN (TCL_ERROR);
              }

     }

     HTMLSetSelection(localVar1,&localVar2,&localVar3);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * void 
 * HTMLSetText	
 * 	in: HTMLWidget         # HTML Widget
 * 	in: String             # Text
 * 	in: String	       # Header Text
 * 	in: String	       # Footer Text
 * 	in: int		       # element_id
 * 	in: String	       # target_anchor
 * 	const: NULL
 */

int 
com_HTMLSetText(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar5;

     DBUG_ENTER("HTMLSetText");  

     if (argc != 7) 
	 {
	 argcError("HTMLSetText","",6,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLSetText","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

    /* no need to assign  << localVar2 = argv[2] >>  */ 

    /* no need to assign  << localVar3 = argv[3] >>  */ 

    /* no need to assign  << localVar4 = argv[4] >>  */ 

     if (!(sscanf(argv[5], "%d", &localVar5)))
          {
          convError("HTMLSetText","5",argv[5],"int");
          DBUG_RETURN (TCL_ERROR);
          }

    /* no need to assign  << localVar6 = argv[6] >>  */ 

     HTMLSetText(localVar1,argv[2],argv[3],argv[4],localVar5,argv[6],NULL);

     DBUG_RETURN (TCL_OK);
     }     


#define searchtext(w, s, instart, outstart, outend, back, sens) HTMLSearchText(w, s, instart, outend, back, sens); (*outstart).id = (*instart).id; (*outstart).pos = (*instart).pos;

/* 
 * int 
 * searchtext vulgo HTMLSearchText
 * 	in: HTMLWidget         # HTML Widget
 * 	in: String             # Pattern
 * 	in: ElementRef         # Input: Start
 * 	out: ElementRef        # Result: Start
 * 	out: ElementRef        # Result: End
 * 	in: int		       # Backward ? (Should be Boolean ?)
 * 	in: int		       # Case Sensitive ? (Should be Boolean ?)
 */

int 
com_HTMLSearchText(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     ElementRef localVar3;
     ElementRef localVar4;
     ElementRef localVar5;
     int localVar6;
     int localVar7;
     int returnVar;
     char conversionBuffer[100];

     DBUG_ENTER("HTMLSearchText");  

     if (argc != 8) 
	 {
	 argcError("HTMLSearchText","",7,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLSearchText","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

    /* no need to assign  << localVar2 = argv[2] >>  */ 

     { char *charp;
         if (!(charp=Tcl_GetVar2(wafeInterpreter,argv[3],"id", 0)))
               {
               noVarCompError("HTMLSearchText",argv[3],"id");
               DBUG_RETURN (TCL_ERROR);
               }
         if (!(sscanf(charp, "%d", &localVar3.id)))
              {
              convError("HTMLSearchText","3.id",charp,"int");
              DBUG_RETURN (TCL_ERROR);
              }

         if (!(charp=Tcl_GetVar2(wafeInterpreter,argv[3],"pos", 0)))
               {
               noVarCompError("HTMLSearchText",argv[3],"pos");
               DBUG_RETURN (TCL_ERROR);
               }
         if (!(sscanf(charp, "%d", &localVar3.pos)))
              {
              convError("HTMLSearchText","3.pos",charp,"int");
              DBUG_RETURN (TCL_ERROR);
              }

     }

     if (!(sscanf(argv[6], "%d", &localVar6)))
          {
          convError("HTMLSearchText","6",argv[6],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[7], "%d", &localVar7)))
          {
          convError("HTMLSearchText","7",argv[7],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     returnVar = searchtext(localVar1,argv[2],&localVar3,&localVar4,&localVar5,localVar6,localVar7);

          sprintf(conversionBuffer, "%d", localVar4.id);
     Tcl_SetVar2(wafeInterpreter,argv[4],"id", conversionBuffer,0);
     sprintf(conversionBuffer, "%d", localVar4.pos);
     Tcl_SetVar2(wafeInterpreter,argv[4],"pos", conversionBuffer,0);


          sprintf(conversionBuffer, "%d", localVar5.id);
     Tcl_SetVar2(wafeInterpreter,argv[5],"id", conversionBuffer,0);
     sprintf(conversionBuffer, "%d", localVar5.pos);
     Tcl_SetVar2(wafeInterpreter,argv[5],"pos", conversionBuffer,0);


     sprintf(conversionBuffer, "%d", returnVar);
     Tcl_SetResult(comInterpreter, conversionBuffer, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * void
 * HTMLGotoId
 * 	in: HTMLWidget		# HTML Widget
 * 	in: int 		# Element ID
 */

int 
com_HTMLGotoId(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar2;

     DBUG_ENTER("HTMLGotoId");  

     if (argc != 3) 
	 {
	 argcError("HTMLGotoId","",2,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLGotoId","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[2], "%d", &localVar2)))
          {
          convError("HTMLGotoId","2",argv[2],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     HTMLGotoId(localVar1,localVar2);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * int
 * HTMLAnchorToId
 * 	in: HTMLWidget		# HTML Widget
 * 	in: String			# Anchor string
 */

int 
com_HTMLAnchorToId(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int returnVar;
     char conversionBuffer[100];

     DBUG_ENTER("HTMLAnchorToId");  

     if (argc != 3) 
	 {
	 argcError("HTMLAnchorToId","",2,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLAnchorToId","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

    /* no need to assign  << localVar2 = argv[2] >>  */ 

     returnVar = HTMLAnchorToId(localVar1,argv[2]);

     sprintf(conversionBuffer, "%d", returnVar);
     Tcl_SetResult(comInterpreter, conversionBuffer, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * Boolean
 * HTMLIdToElement
 * 	in: HTMLWidget		# HTML Widget
 * 	in: int	       		# Element ID
 * 	out: HTMLElementRecord* # Element Record
 */

int 
com_HTMLIdToElement(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar2;
     HTMLElementRecord* localVar3;
     Boolean returnVar;
     char conversionBuffer[100];

     DBUG_ENTER("HTMLIdToElement");  

     if (argc != 4) 
	 {
	 argcError("HTMLIdToElement","",3,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLIdToElement","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[2], "%d", &localVar2)))
          {
          convError("HTMLIdToElement","2",argv[2],"int");
          DBUG_RETURN (TCL_ERROR);
          }

     returnVar = HTMLIdToElement(localVar1,localVar2,&localVar3);

          
     Tcl_SetVar2(wafeInterpreter,argv[3],"anchorName", localVar3->anchorName,0);
     
     Tcl_SetVar2(wafeInterpreter,argv[3],"anchorHRef", localVar3->anchorHRef,0);
     
     Tcl_SetVar2(wafeInterpreter,argv[3],"edata", localVar3->edata,0);


          if (returnVar == 1) 
          strcpy(conversionBuffer, "true");
     else
     if (returnVar == 0) 
          strcpy(conversionBuffer, "false");


     Tcl_SetResult(comInterpreter, conversionBuffer, TCL_VOLATILE);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * void
 * HTMLsetElementBg
 * 	in: HTMLWidget 		# HTML Widget
 * 	in: int	       		# Element ID
 * 	in: String              # backgroundColor
 */

int 
com_HTMLsetElementBg(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;
     int localVar2;

     DBUG_ENTER("HTMLsetElementBg");  

     if (argc != 4) 
	 {
	 argcError("HTMLsetElementBg","",3,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLsetElementBg","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     if (!(sscanf(argv[2], "%d", &localVar2)))
          {
          convError("HTMLsetElementBg","2",argv[2],"int");
          DBUG_RETURN (TCL_ERROR);
          }

    /* no need to assign  << localVar3 = argv[3] >>  */ 

     HTMLsetElementBg(localVar1,localVar2,argv[3]);

     DBUG_RETURN (TCL_OK);
     }     


/* 
 * void 
 * HTMLRetestAnchors
 * 	in: HTMLWidget		# HTML Widget
 * 	const: NULL

 */

int 
com_HTMLRetestAnchors(clientData, comInterpreter, argc, argv)
ClientData    clientData;
Tcl_Interp   *comInterpreter;
int           argc;
char        **argv;
     {
     Widget localVar1;

     DBUG_ENTER("HTMLRetestAnchors");  

     if (argc != 2) 
	 {
	 argcError("HTMLRetestAnchors","",1,argc);
	 DBUG_RETURN (TCL_ERROR);
         }

     if (!(localVar1 =  name2WidgetOfClass(argv[1],hTMLWidgetClass,"HTML")))
          {
          convError("HTMLRetestAnchors","1",argv[1],"HTMLWidget");
          DBUG_RETURN (TCL_ERROR);
          }

     HTMLRetestAnchors(localVar1,NULL);

     DBUG_RETURN (TCL_OK);
     }     


#else
#include "wafe.h"
#endif

void
Initialize_htmlwGen()
{
#ifdef HTML
 createWidgetCommand("HTML",htmlWidgetClass,crtHtmlWidget,False);
#ifdef HTML
 strcat(wafePackages,"HTML ");
#endif
 qimageList = WafePermStringToQuark("imageList");
 Tcl_CreateCommand(wafeInterpreter, "HTMLGetText", com_HTMLGetText, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLGetTextAndSelection", com_HTMLGetTextAndSelection, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLGetHRefs", com_HTMLGetHRefs, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLPositionToId", com_HTMLPositionToId, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLIdToPosition", com_HTMLIdToPosition, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLAnchorToPosition", com_HTMLAnchorToPosition, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLClearSelection", com_HTMLClearSelection, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLSetSelection", com_HTMLSetSelection, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLSetText", com_HTMLSetText, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLSearchText", com_HTMLSearchText, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLGotoId", com_HTMLGotoId, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLAnchorToId", com_HTMLAnchorToId, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLIdToElement", com_HTMLIdToElement, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLsetElementBg", com_HTMLsetElementBg, NULL, NULL);
 Tcl_CreateCommand(wafeInterpreter, "HTMLRetestAnchors", com_HTMLRetestAnchors, NULL, NULL);

#else
#endif
}
