/****************************************************************/
/*                                                              */
/* rdlog2.c (see readme.html for program explanation            */
/*                                                              */
/* author : Philippe Simonet, sip00@vg.swissptt.ch              */
/*                                                              */
/* change log :                                                 */
/*                                                              */
/* v. 1.00 : initial update (SIP) (02.12.97                     */
/*                                                              */
/*                                                              */
/*                                                              */


/************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include "gd.h"
#include "gdfonts.h"

#define FALSE		0
#define TRUE		1

#define	TEXT		1
#define	RECT		2
#define	POLY		3
#define	COLOR		4
#define	COLORDEF	5
#define	LINK		6
#define	COMPOUND	7
#define	ENDCOMPOUND	8
#define	GIFAREA		9
#define	URL			10
#define	IN			11
#define	OUT			12
#define	INOUT		13
#define	UNKNOWN		99


#ifndef max
 #define max(a,b) ((a)>(b))?(a):(b)
#endif

#ifndef min
 #define min(a,b) ((a)<(b))?(a):(b)
#endif


int colorratetable[256];

int colortable[256] = {
			0x000000,	/* 0  BLACK */
			0xff0000,	/* 1  BLUE */
			0x00ff00,	/* 2  GREEN*/
			0xffff00,	/* 3  CYAN */
			0x0000ff,	/* 4  RED */
			0xff00ff,	/* 5  MAGENTA */
			0x00ffff,	/* 6  YELLOW */
			0xffffff,	/* 7  WHITE */
			0x900000,	/* 8  Blue4 */
			0xb00000,	/* 9  Blue3 */
			0xd00000,	/* 10 Blue2 */
			0xffce87,	/* 11 LtBlue */
			0x009000,	/* 12 Green4 */
			0x00b000,	/* 13 Green3 */
			0x00d000,	/* 14 Green2 */
			0x909000,	/* 15 Cyan4 */
			0xb0b000,	/* 16 Cyan3 */
			0xd0d000,	/* 17 Cyan2 */
			0x000090,	/* 18 Red4 */
			0x0000b0,	/* 19 Red3 */
			0x0000d0,	/* 20 Red2 */
			0x900090,	/* 21 Magenta4 */
			0xb000b0,	/* 22 Magenta3 */
			0xd000d0,	/* 23 Magenta2 */
			0x003080,	/* 24 Brown4 */
			0x0040a0,	/* 25 Brown3 */
			0x0060c0,	/* 26 Brown2 */
			0x8080ff,	/* 27 Pink4 */
			0xa0a0ff,	/* 28 Pink3 */
			0xc0c0ff,	/* 29 Pink2 */
			0xe0e0ff,	/* 30 Pink */
			0x00d7ff	/* 31 gold */
};

/************************************************************************/
/* each of these entry contain the description of a graphical object    */
struct sentry {
	int		type;			/* text, line, link, poly */
	int		depth;			/* order in which it appears */
	char	* str;			/* log file name, url, text */
	int		maxrate;		/* max xfer rate */
	int		rate;			/* max xfer rate */
	int		orientation;	/* text orientation, ... */
	int		color;			/* color */
	int		fillcolor;		/* color */
	int		colorindex;		/* color index */
	int		npoints;		/* fig size */	
	int		* coords;		/* coordinates list */
	struct sentry * next;	/* next entry */
}; 

int xsize, ysize, rounds, xoffset, yoffset;
struct sentry * pfirstentry, *pcurrententry, *pareaentry;

/************************************************************************/
/* analyze command-line options */
static int		optind = 0; 		/* Global argv index. 	*/
static char		*scan = NULL;  		/* Private scan pointer. */
static int		scale = 15;

int getopt1( int argc, char *argv[], char *optstring, char ** optarg )
{
    int 		c;			/* return value */
    char 		*place;
    char    	*index();

    *optarg = NULL;

							/* check argument validity */
    if (scan == NULL || *scan == '\0') {
        if (optind == 0) optind++;
        if (optind >= argc) return EOF;
        place = argv[optind];
        if (place[0] != '-' || place[1] == '\0') return EOF;
        optind++;
        if (place[1] == '-' && place[2] == '\0') return EOF;
        scan = place+1;
    }

    c = *scan++;			/* get option character */
    place = strchr(optstring, c);
    if (place == NULL || c == ':') return '?';


							/* set optarg if needed */
    if (*++place == ':') {
        if (*scan != '\0') {
        	*optarg = scan; scan = NULL;
        } else {
        	*optarg = argv[optind], optind++;
        }
    }
    return c;
}

/************************************************************************/
/* computes a traffic in % by reading 'rounds' lines in a MRTG log file */
/* currently, it takes the maximum of the In or OUT traffic.            */
void read_entry ( struct sentry * pentry) {

	FILE	* logf;
	int		i, j=0, k=0;

	logf = fopen ( pentry->str, "r" );
	if ( pentry->maxrate == 0 ) {
		fprintf ( stderr, "Max rate for %s is null.\n", pentry->str );
		return;
	}		

	if ( logf != NULL ) {
		fscanf(logf, "%*d %d %d", &j, &k);					/* get first line */

		for ( i = 0; i < rounds; i ++ ) {					/* computes mean */
			fscanf(logf, "%*d %d %d %*d %*d", &j, &k);		/* get line */
			/*printf(" - [%d %d]\n", j, k);*/
			switch (pentry->orientation) {
			case IN:
				pentry->rate += j;
				break;
			case OUT:
				pentry->rate += k;
				break;
			default:
				if ( j > k )	pentry->rate += j;
				else			pentry->rate += k;
				break;
			}
		}		
											/* computes the rate 0-9 */
		pentry->rate = pentry->rate / rounds; 
		/*printf ( "%s : %u, %u.\n", pentry->str, (pentry->maxrate*100)/pentry->maxrate, (pentry->rate*10)/pentry->maxrate );*/
		pentry->rate  = (pentry->rate * 10) / pentry->maxrate;
		if ( pentry->rate > 9 ) pentry->rate = 9;
		if ( pentry->rate < 0 ) pentry->rate = 0;
		fclose ( logf );
	} else {
		fprintf ( stderr, "Cannot open file %s.\n", pentry->str );
	};
}

/************************************************************************/
/* in case of trouble ...                                               */
void print_error ( void )
{ 
	fprintf ( stderr, "Read mrtg configuration files and convert them in gif format.\n" );
	fprintf ( stderr, "Use :\n" );
	fprintf ( stderr, "  rdlog -i cfile -o gfile [-m mapfile] -r rounds\n" );
	fprintf ( stderr, "   ifile : input fig file name,\n" );
	fprintf ( stderr, "   gfile : output gif file (will be overwritten),\n" );
	fprintf ( stderr, "   mapfile : output map file (optional, will be overwritten),\n" );
	fprintf ( stderr, "   rounds : number of 5 min intervals to take.\n" );
}

/************************************************************************/
/* free an 'entry' variable                                             */
void free_entry (struct sentry * pentry) {
	if ( pentry!= NULL ) {
		if ( pentry->str != NULL ) free(pentry->str); pentry->str = NULL;
		if ( pentry->coords != NULL ) free(pentry->coords); pentry->coords = NULL;
		free(pentry);
	}
}


/************************************************************************/
/* print an entry for debug purpose                                     */
void print_entry (struct sentry * pentry) {

	printf ( "Entry : " );
	if ( pentry->str != NULL )	printf ( "str '%s' ", pentry->str );
	printf ( ".\n type %i, maxrate %i, orientation %i, npoints %i, color %i, depth %i.\n",
		pentry->type,pentry->maxrate,pentry->orientation,pentry->npoints,pentry->color,pentry->depth );
}

/************************************************************************/
int new_entry( void ) {

	struct sentry * pentry;

	if ( ( pentry = malloc ( sizeof (struct sentry) )) == NULL ) {
		fprintf ( stderr, "Error : memory allocation failure.\n" );
		return ( FALSE );
	}

	if ( pfirstentry == NULL ) {
		pfirstentry = pentry;
	} else {
		pcurrententry->next = pentry;
	}

	pentry->type		=	UNKNOWN;		
	pentry->str			=	NULL;		
	pentry->maxrate		=	0;	
	pentry->rate		=	0;		
	pentry->orientation	=	0;
	pentry->color		=	0;	
	pentry->fillcolor	=	0;	
	pentry->depth		=	0;	
	pentry->colorindex	=	0;	
	pentry->npoints		=	0;
	pentry->coords		=	NULL;
	pentry->next		=	NULL;

	pcurrententry = pentry;

return ( TRUE );
}


/************************************************************************/
#define r(color) ((color&0x0000ff)>>0)
#define g(color) ((color&0x00ff00)>>8)
#define b(color) ((color&0xff0000)>>16)
#define rgb(color) ((color&0x0000ff)>>0),((color&0x00ff00)>>8),((color&0xff0000)>>16)

/************************************************************************/
/* build a color or find the nearest color in the color table           */ 
int find_color ( gdImagePtr graph, int color ) {
	int i_col;

	if ( (i_col = gdImageColorExact(graph,r(color), g(color), b(color))) == -1 ) {
		if ( (i_col = gdImageColorAllocate(graph,r(color), g(color), b(color))) == -1 ) {
			i_col = gdImageColorClosest(graph,r(color), g(color), b(color));
		}
	}
	return (i_col);
}


/************************************************************************/
/* draw the gif file, based on the tentry desciption                    */
void draw_gif ( FILE * gif )
{
	#define c_blank 245,245,245	/* base colors */
	#define c_light 194,194,194
	#define c_dark 100,100,100
	#define c_black 0,0,0
	#define c_white 255,255,0

    gdImagePtr graph;
	int i_light,i_dark,i_blank, i_black, i_white;
	int bkcolor;

    graph = gdImageCreate(xsize, ysize);

    /* the first color allocated will be the background color. */
	bkcolor = colortable[pareaentry->fillcolor];
    i_blank = gdImageColorAllocate(graph,rgb(bkcolor));
    i_light = gdImageColorAllocate(graph,c_light);
    i_dark = gdImageColorAllocate(graph,c_dark);

    gdImageInterlace(graph, 1); 

    i_black = gdImageColorAllocate(graph,c_black);
    i_white = gdImageColorAllocate(graph,c_white);

    /* draw the image border */
    gdImageLine(graph,0,0,xsize-1,0,i_light);
    gdImageLine(graph,1,1,xsize-2,1,i_light);
    gdImageLine(graph,0,0,0,ysize-1,i_light);
    gdImageLine(graph,1,1,1,ysize-2,i_light);
    gdImageLine(graph,xsize-1,0,xsize-1,ysize-1,i_dark);
    gdImageLine(graph,0,ysize-1,xsize-1,ysize-1,i_dark);
    gdImageLine(graph,xsize-2,1,xsize-2,ysize-2,i_dark);
    gdImageLine(graph,1,ysize-2,xsize-2,ysize-2,i_dark);

	{									/* date the graph */
		struct tm *newtime;
		time_t aclock;
		time( &aclock );				/* Get time in seconds */
		newtime = localtime( &aclock ); /* Convert time to struct */
										/* tm form */

		gdImageString(graph, gdFontSmall,3,3,asctime( newtime ),i_dark);
	};
	

	while ( 1 ) {
		int i_col, i_col2, depth;
		struct sentry * pentry;

		/* find smallest depth */
		pentry = pfirstentry;
		depth = -1;
		while ( pentry != NULL ) {
			if (pentry->depth > depth) {
				depth = pentry->depth;
				pcurrententry = pentry;
			}
			pentry = pentry->next;
		}
		if ( depth == -1 ) break;
		pcurrententry->depth = -1;

		/* draw this fig */
		switch ( pcurrententry->type) {
		case RECT:
			i_col = find_color(graph, colortable[pcurrententry->color]);


			if ( pcurrententry->fillcolor != -1 ) {

				i_col2 = find_color(graph, colortable[pcurrententry->fillcolor]);

				gdImageFilledRectangle(graph,	
									pcurrententry->coords[0],
									pcurrententry->coords[1],
									pcurrententry->coords[2],
									pcurrententry->coords[3],i_col2);
			}

			gdImageRectangle(graph,	
								pcurrententry->coords[0],
								pcurrententry->coords[1],
								pcurrententry->coords[2],
								pcurrententry->coords[3],i_col);
			break;
		case TEXT:
			i_col = find_color(graph, colortable[pcurrententry->color]);
			if (pcurrententry->orientation == 0) {
				gdImageString(graph, gdFontSmall,
					pcurrententry->coords[0],
					pcurrententry->coords[1],
					pcurrententry->str,
					i_col );
			} else {
				gdImageStringUp(graph, gdFontSmall,
					pcurrententry->coords[0],
					pcurrententry->coords[1],
					pcurrententry->str,
					i_col );
			}
			break;
		case POLY:
		case LINK:
			{
				int x = pcurrententry->coords[0];
				int y = pcurrententry->coords[1];
				int x2, y2, j, k;
				gdImagePtr brush_2pix;

				if (pcurrententry->type == POLY) {
					i_col = find_color(graph, colortable[pcurrententry->color]);
				} else {
					brush_2pix = gdImageCreate(2,2);
					gdImageColorAllocate(
						brush_2pix,
						r(colortable[colorratetable[pcurrententry->rate]]),
						g(colortable[colorratetable[pcurrententry->rate]]),
						b(colortable[colorratetable[pcurrententry->rate]]) );
				    gdImageSetBrush(graph, brush_2pix);
					i_col = gdBrushed;
				}
	
				k = 2;
				for ( j = 1; j < pcurrententry->npoints; j ++ ) {
					x2 = pcurrententry->coords[k++];
					y2 = pcurrententry->coords[k++];
					gdImageLine(graph,	x, y, x2, y2,i_col);
					x = x2; y = y2;
				};

				if (pcurrententry->type == LINK) {
				    gdImageDestroy(brush_2pix);
				};
			
			}

			break;
		default:
			break;
		}
		pcurrententry = pcurrententry->next;
	}

    gdImageGif(graph, gif);    

    gdImageDestroy(graph);
}		


struct sfigrec {
	int		type;
	char	text[500];
	int		colorindex;
	int		depth;
	int		color;
	int		fillcolor;
	int		angle;
	int		coords[500];
	int		npoints;
}; 


/************************************************************************/
int getfig ( FILE * config, struct sfigrec * fig ) 
{
	char		buf[1000], str[1000], *s;
	int			i, n, type, color, colorindex, depth, pen_style, font, flags, x, y;
	int			style, thickness, pen_color, fill_color, fill_style, join_style, cap_style, radius, fa, ba, npts;
	float		tx_size, angle, style_val;

	fig->type = UNKNOWN;

	if ( fgets (buf, 1000, config ) == NULL ) {
		return ( TRUE );
	}

	switch ( buf[0] ) {
	case '0':	/* color ref */
			n = sscanf(buf, "%*d %d #%06x", &colorindex, &color );
			/*printf ( "colordef : %d, %d.\n", colorindex, color );*/
			fig->type = COLORDEF;
			fig->color = ((color & 0xff0000)>>16) | (color & 0x00ff00) | ((color & 0x0000ff)<<16);
			fig->colorindex = colorindex;
			break;
	case '2':	/* polyline */
			n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%f%d%d%d%d%d%d",
				   &type, &style, &thickness, &pen_color, &fill_color,
				   &depth, &pen_style, &fill_style, &style_val,
				   &join_style, &cap_style, &radius, &fa, &ba, &npts);
			/*puts ( buf );*/
			/*printf ("type %d, style %d, thickness %d, pen_color %d, fill_color %d, depth %d, pen_style %d, fill_style %d, style_val %f, join_style %d, cap_style %d, radius %d, fa %d, ba %d, npts %d ",
				   type, style, thickness, pen_color, fill_color,
				   depth, pen_style, fill_style, style_val,
				   join_style, cap_style, radius, fa, ba, npts);*/
			fig->depth = depth;
			fig->color = pen_color;
			fig->npoints = npts;
			for ( i = 0; i < npts; i ++ ) {
				fscanf(config, "%d%d", &x, &y);
				fig->coords[i*2] = x; fig->coords[i*2+1] = y;
				/*printf ( "[%d %d] ", x, y );*/
			}
			fig->type = POLY;
			if ( type == 2 ) { /* rectangle */
				fig->type = RECT;
				if ( fill_style == -1 ) {
					fig->fillcolor = -1;
				} else {
					fig->fillcolor = fill_color;
				}
				x = min(fig->coords[0],fig->coords[4]);
				y = min(fig->coords[1],fig->coords[5]);
				fig->coords[2] = max(fig->coords[0],fig->coords[4]);
				fig->coords[3] = max(fig->coords[1],fig->coords[5]);
				fig->coords[0] = x;
				fig->coords[1] = y;
				fig->npoints = 2;
			}
			/*printf ( ".\n" );*/
			break;
	case '4':	/* text */
			n = sscanf(buf, "%*d%d%d%d%d%d%f%f%d%*f%*f%d%d %[^\n]",
				&type, &color, &depth, &pen_style, &font, &tx_size, &angle,	&flags, &x, &y, str);
			s = strstr ( str, "\\001" );
			if ( s != NULL ) s[0] = 0;
			/*printf ( "text : type %d, color %d, depth %d, pen_style %d, font %d, ty_size %f, angle %f, flags %d, x %d, y %d, s [%s].\n",
				type, color, depth, pen_style, font, tx_size, angle, flags, x, y, str );*/
			fig->type = TEXT;
			strcpy (fig->text, str);
			fig->depth = depth;
			fig->color = color;
			if ( angle < 1) {
				fig->angle = 0;
				fig->coords[0] = x;
				fig->coords[1] = y-150;
			} else {
				fig->angle = 1;
				fig->coords[0] = x-150;
				fig->coords[1] = y;
			}
			fig->npoints = 1;
			break;
	case '6':	/* compound */
			fig->type = COMPOUND;
			/*printf ( "compound.\n" );*/
			break;
	case '-':	/* compound end */
			fig->type = ENDCOMPOUND;
			/*printf ( "end of compound.\n" );*/
			break;
	default:
			break;
	}
	
	return ( FALSE );

}


/************************************************************************/
void main ( int argc, char * argv[] )
{
	FILE			*config = NULL, *gif = NULL, *map = NULL;		
	char 			*sconfig = NULL, *sgif = NULL, *smap = NULL;
	char 			*optarg;
	int				i; 

	/* globals */
	xsize = 100, ysize = 100;
	rounds = 6;

	do	{
		/***************************************************************/
		/* 0 : read program arguments */
		while ( ( i = getopt1( argc, argv, "o:i:r:m:", &optarg ) ) != EOF ) {
			switch ( i ) {
				case 'i':
					sconfig = optarg;
					break;
				case 'o':			
					sgif = optarg;
					break;
				case 'm':			
					smap = optarg;
					break;
				case 'r':			
					rounds = atoi (optarg);
					if ( rounds < 1 ) {
						print_error();
						exit (0);
					};
					break;
				case '?':			
					print_error();
					exit (0);
					break;
				default:
					break;
			}
		}


		if ( sconfig == NULL || sgif == NULL ) {
			print_error();
			break;
		}

	
		/***************************************************************/
		/* 1 : OPEN FILES */
		config = fopen ( sconfig, "r" );
		if ( config == NULL ) {
			fprintf ( stderr, "Error opening %s.\n", sconfig );
			break;
		}

		gif = fopen ( sgif, "wb" );
		if ( gif == NULL ) {
			fprintf ( stderr, "Error opening %s.\n", sgif );
			fclose ( config );
			break;
		}

		if ( smap != NULL ) {
			map = fopen ( smap, "w" );
			if ( map == NULL ) {
				fprintf ( stderr, "Error opening %s.\n", sgif );
				fclose ( config );
				fclose ( gif );
				break;
			}
			fprintf ( map, "  <map name=\"map1\">\n" );
		}


		/***************************************************************/
		/* 2 : SCAN CONFIG FILE */
		pcurrententry = NULL; pfirstentry = NULL; pareaentry = NULL;
		for ( i = 0; i < 256; i++ ) {
			colorratetable[i] = 0;
		}
		for ( i = 32; i < 256; i++ ) {
			colortable[i] = 0;
		}

		while ( TRUE ) {
			struct sfigrec	figrec;

			/********************************************/
			/* get one fig record */
			if ( getfig ( config, &figrec ) == TRUE ) break;

			switch (figrec.type) {
			case COLORDEF:
				if ( figrec.colorindex < 256 ) colortable[figrec.colorindex] = figrec.color;
				/*printf ( "color table[%i] : %i.\n", figrec.colorindex, colortable[figrec.colorindex] );*/
				break;
			case TEXT:
				if ( new_entry() == FALSE ) break;
				pcurrententry->type = UNKNOWN;
				pcurrententry->color = figrec.color;
				pcurrententry->depth = figrec.depth;

				if ( strncmp("color:", figrec.text, 6 ) == 0 ) { /* special 'color:' text */
					i = atoi ( figrec.text+6 );
					if ( i < 256 ) colorratetable[i] = figrec.color;
					/*printf ( "color rate[%i] : %i.\n", i, colorratetable[i] );*/
					break;
				}

				if ( (pcurrententry->str = malloc ( strlen(figrec.text) + 1 )) == NULL ) {
					fprintf ( stderr, "Error : memory allocation failure.\n" );
					break;
				}
				if ( (pcurrententry->coords = (int *)malloc(figrec.npoints * (sizeof (int)) * 2 )) == NULL ) {
					fprintf ( stderr, "Error : memory allocation failure.\n" );
					break;
				}
				pcurrententry->type = TEXT;
				pcurrententry->npoints = figrec.npoints;
				pcurrententry->orientation = figrec.angle;
				strcpy (pcurrententry->str,figrec.text);
				memcpy (pcurrententry->coords,figrec.coords,figrec.npoints * (sizeof (int)) * 2);
				break;
			case POLY:
			case RECT:
				if ( new_entry() == FALSE ) break;
				pcurrententry->type = UNKNOWN;
				pcurrententry->depth = figrec.depth;
				pcurrententry->color = figrec.color;
				pcurrententry->fillcolor = figrec.fillcolor;
				if ( (pcurrententry->coords = (int *)malloc(figrec.npoints * (sizeof (int)) * 2 )) == NULL ) {
					fprintf ( stderr, "Error : memory allocation failure.\n" );
					continue;
				}
				pcurrententry->type = figrec.type;
				pcurrententry->npoints = figrec.npoints;
				memcpy (pcurrententry->coords,figrec.coords,figrec.npoints * (sizeof (int)) * 2);
				break;
			case COMPOUND:			/* compound must be links ... */
				if ( new_entry() == FALSE ) break;
				do {
					if ( getfig ( config, &figrec ) == TRUE ) break;
					if ( figrec.type == ENDCOMPOUND ) break;
					if ( figrec.type == TEXT ) {
						/*printf (" txt %s.\n", figrec.text );*/
						if ( strncmp("gifarea", figrec.text, 7 ) == 0 ) {
							pcurrententry->type = GIFAREA;
							pareaentry = pcurrententry;
							/*printf ( " gifarea : [%i / %i] ", pcurrententry->coords[0], pcurrententry->coords[1]);
							printf ( " [%i / %i].\n", pcurrententry->coords[2], pcurrententry->coords[3]);*/
						} else if ( strncmp("url:", figrec.text, 4 ) == 0 ) {
							if ( (pcurrententry->str = malloc ( strlen(figrec.text) + 1 )) == NULL ) {
								fprintf ( stderr, "Error : memory allocation failure.\n" );
								break;
							}
							pcurrententry->type = URL;
							strcpy (pcurrententry->str,figrec.text+4);
							/*printf (" url %s.\n", pcurrententry->str );*/
						} else if ( strncmp("log:", figrec.text, 4 ) == 0 ) {
							char * s = figrec.text + 4;
							if ( s[0] == '>' ) {
								pcurrententry->orientation = OUT;
								s++;
							} else if ( s[0] == '<' ) {
								pcurrententry->orientation = IN;
								s++;
							} else {
								pcurrententry->orientation = INOUT;
							}
							if ( (pcurrententry->str = malloc ( strlen(s) + 1 )) == NULL ) {
								fprintf ( stderr, "Error : memory allocation failure.\n" );
								break;
							}
							pcurrententry->type = LINK;
							strcpy (pcurrententry->str,s);
							/*printf (" str %s.\n", pcurrententry->str );*/
						} else if ( strncmp("speed:", figrec.text, 6 ) == 0 ) {
							pcurrententry->maxrate = atoi ( figrec.text+6 );
							/*printf (" max rate : %i.\n", pcurrententry->maxrate );*/
						}
					}
					if ( (figrec.type == POLY) || (figrec.type == RECT) ) {
						pcurrententry->color = figrec.color; /* default color */
						pcurrententry->depth = figrec.depth;
						pcurrententry->fillcolor = figrec.fillcolor; 
						if ( (pcurrententry->coords = (int *)malloc(figrec.npoints * (sizeof (int)) * 2 )) == NULL ) {
							fprintf ( stderr, "Error : memory allocation failure.\n" );
							break;
						}
						pcurrententry->npoints = figrec.npoints;
						memcpy (pcurrententry->coords,figrec.coords,figrec.npoints * (sizeof (int)) * 2);
					}
				} while ( 1 );
				if ( pcurrententry->type==LINK && pcurrententry->coords != NULL ) {
					read_entry ( pcurrententry );
					/*printf (" link : log : %s.log, max rate : %i.\n", pcurrententry->str, pcurrententry->maxrate );*/
				}
				break;
			case ENDCOMPOUND:
			case UNKNOWN:
			default:
				break;
			}

		}

		/***************************************************************/
		/* checks */
		if ( pareaentry == NULL ) {
			fprintf ( stderr, "Error : no gif area specified.\n");
			break;
		}
		xsize = (pareaentry->coords[2] - pareaentry->coords[0]);
		ysize = (pareaentry->coords[3] - pareaentry->coords[1]);
		xoffset = pareaentry->coords[0]; yoffset = pareaentry->coords[1];
		/*printf ( "size : %i %i.\n", xsize, ysize );
		printf ( "offset : %i %i.\n", xoffset, yoffset );*/

		/***************************************************************/
		/*  do translations	                                           */
		pcurrententry = pfirstentry;
		while ( pcurrententry != NULL ) {
			for (i = 0; i < pcurrententry->npoints; i ++) {
				pcurrententry->coords[i*2]		-=	xoffset;
				pcurrententry->coords[i*2+1]	-=	yoffset;
				pcurrententry->coords[i*2] /= scale;
				pcurrententry->coords[i*2+1] /= scale;
			}
			if ( smap != NULL ) {
				if ( pcurrententry->type==URL && pcurrententry->coords != NULL ) {
					fprintf ( map, "   <area href=%s alt=\"%s\" shape=rect coords=\"%i,%i,%i,%i\">\n", 
						pcurrententry->str,pcurrententry->str,
						pcurrententry->coords[0],pcurrententry->coords[1],
						pcurrententry->coords[2],pcurrententry->coords[3] );
				}
			}
			pcurrententry = pcurrententry->next;
		}
		xsize /= scale; ysize /=scale;

		/***************************************************************/
		/* 3 : draw gif file                                           */
		draw_gif ( gif );
		
		/***************************************************************/
		/* 4 : clean-up all											   */
		{
			struct sentry * pentry;
			pcurrententry = pfirstentry;
			do {
				pentry = pcurrententry->next;
				free_entry(pcurrententry);
				pcurrententry = pentry;
			} while ( pentry != NULL );
		}
		
		fclose ( gif );
		fclose ( config );

		if ( smap != NULL ) {
			/*<area href=lk311.html alt="lk311.html" shape=rect coords="240,12,270,24">*/
			fprintf ( map, "  </map>\n" );
			fclose ( map );
		}
		
		break;

	} while ( TRUE );

}

