view colormap.c @ 98:c856945880be

Remove debugging
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 17 Dec 2006 11:57:21 +0000
parents c094c3637841
children 834bbe2fbb51
line wrap: on
line source

/*
 * Convert BatMUD ASCII map to different formats
 * Programmed by Matti 'ccr' Hämäläinen (Ggr Pupunen)
 * (C) Copyright 2006 Tecnic Software productions (TNSP)
 */
#include "maputils.h"
#include "th_args.h"
#include "th_string.h"


typedef struct {
	char *fmtName;
	char *fmtDescription;
	BOOL supBackColor;
	void (*putTagStart) (FILE *, int);
	void (*putTagEnd) (FILE *);
	BOOL (*putTagEOL) (FILE *);
	void (*putFileStart) (FILE *);
	void (*putFileEnd) (FILE *);
} outfmt_t;


char	*srcFilename = NULL,
	*destFilename = NULL;

char	*optXHTMLTagName = "i",
	*optMapTitle = NULL;
	
BOOL	optPerformAnalysis = FALSE,
	optInputIsDiff = FALSE,
	optUseOldFormat = FALSE,
	optCheatMode = FALSE;

int	optOutputFormat = 0,
	optBackColor = 0;

	
/* Arguments
 */
optarg_t optList[] = {
	{ 0, '?', "help",	"Show this help", OPT_NONE },
	{ 1, 'v', "verbose",	"Be more verbose", OPT_NONE },
	{ 2, 'q', "quiet",	"Be quiet", OPT_NONE },
	{ 3, 'T', "html-tag",	"XHTML tag used for map", OPT_ARGREQ },
	{ 4, 'a', "analysis",	"Perform statistical analysis", OPT_NONE },
	{ 5, 'd', "input-diff",	"Input is a diff", OPT_NONE },
	{ 6, 'O', "old-format",	"Input using old symbols/colors", OPT_NONE },
	{ 7, 'o', "output",	"Output filename", OPT_ARGREQ },
	{ 8, 'f', "format",	"Specify output format", OPT_ARGREQ },
	{ 9, 't', "title",	"Map title", OPT_ARGREQ },
	{ 10,'C', "cheat-mode",	"Use cheating in HTML", OPT_NONE },
};

const int optListN = (sizeof(optList) / sizeof(optarg_t));


/*
 * ANSI output format functions
 */
void putTagStartANSI(FILE *outFile, int c)
{
	fputc(0x1b, outFile);

	if (c < 0) {
		fprintf(outFile, "[0;47;30m");
	} else {
		fprintf(outFile, "[0;%d;%dm",
			mapColors[c].ansiAttr,
			mapColors[c].ansi);
	}
}

void putTagEndANSI(FILE *outFile)
{
	(void) outFile;
	/*
	fputc(0x1b, outFile);
	fprintf(outFile, "[0m");
	*/
}

BOOL putEOLANSI(FILE *outFile)
{
	fprintf(outFile, "\n");
	return TRUE;
}

void putFileStartANSI(FILE *outFile)
{
	fputc(0x1b, outFile);
	fprintf(outFile, "[0m");

	if (optMapTitle) {
		fprintf(outFile, "%s\n", optMapTitle);
	}
}


void putFileEndANSI(FILE *outFile)
{
	fputc(0x1b, outFile);
	fprintf(outFile, "[0m");
}


/*
 * ASCII output format functions
 */
void putTagStartText(FILE *outFile, int c)
{
	(void) outFile; (void) c;
//	fprintf(outFile, "§");
}

void putTagEndText(FILE *outFile)
{
	(void) outFile;
//	fprintf(outFile, "$");
}

BOOL putEOLText(FILE *outFile)
{
	fprintf(outFile, "\n");
	return FALSE;
}

void putFileStartText(FILE *outFile)
{
	if (optMapTitle) {
		fprintf(outFile, "%s\n", optMapTitle);
	}
}


void putFileEndText(FILE *outFile)
{
	(void) outFile;
}


/*
 * XHTML+CSS output format functions
 */
#define XHTML_LOCTITLE_SPEC 'q'

void putTagStartXHTML(FILE *outFile, int c)
{
	int q;
	
	if (c < 0)
		q = XHTML_LOCTITLE_SPEC;
	else
		q = 'a'+c;
	
	if (optCheatMode)
		fprintf(outFile, "<i class=%c>", q);
	else
		fprintf(outFile, "<i class='%c'>", q);
}

void putTagEndXHTML(FILE *outFile)
{
	fprintf(outFile, "</i>");
}

BOOL putEOLXHTML(FILE *outFile)
{
	fprintf(outFile, "\n");
	return FALSE;
}

void putFileStartXHTML(FILE *outFile)
{
	mcXHTMLhead(outFile, optMapTitle);
	
	fprintf(outFile,
	" <style type=\"text/css\">\n"
	"  h2 { color: white; }\n"
	"  body { background: black; color: %s; }\n"
	"  %s { text-decoration: none; font-style: normal; }\n"
	"  %s.%c { background: white; color: black; }\n",
	mapColors[optBackColor].css,
	optXHTMLTagName,
	optXHTMLTagName, XHTML_LOCTITLE_SPEC
	);
	
	mcXHTMLcolors(outFile, optXHTMLTagName);

	fprintf(outFile,
	" </style>\n"
	"</head>\n"
	"<body>\n"
	);

	if (optMapTitle)
	fprintf(outFile, "<h2>%s</h2>\n", optMapTitle);

	fprintf(outFile,
	"<pre>\n"
	);
}

void putFileEndXHTML(FILE *outFile)
{
	/* XHTML document end tags */
	fprintf(outFile,
	"</pre>\n"
	"</body>\n"
	"</html>\n"
	);
}


/*
 * Old HTML output format functions
 */
void putTagStartHTML(FILE *outFile, int c)
{
	if (c < 0) {
		fprintf(outFile,
		"<font bgcolor='white' color='black'>");
	} else {
		fprintf(outFile, "<font color='%s'>",
		mapColors[c].css);
	}
}

void putTagEndHTML(FILE *outFile)
{
	fprintf(outFile, "</font>");
}

BOOL putEOLHTML(FILE *outFile)
{
	fprintf(outFile, "\n");
	return FALSE;
}

void putFileStartHTML(FILE *outFile)
{
	fprintf(outFile,
	"<html>\n"
	"<head>\n"
	);
	
	if (optMapTitle)
	fprintf(outFile, " <title>%s</title>\n", optMapTitle);
	
	fprintf(outFile,
	"</head>\n"
	"<body bgcolor='black' text='%s'>\n",
	mapColors[optBackColor].css
	);

	if (optMapTitle)
	fprintf(outFile, "<h2>%s</h2>\n", optMapTitle);

	fprintf(outFile,
	"<pre>\n"
	);
}

void putFileEndHTML(FILE *outFile)
{
	fprintf(outFile,
	"</pre>\n"
	"</body>\n"
	"</html>\n"
	);
}


/* Process a normal format input
 */
void processNormal(FILE *inFile, FILE *outFile, outfmt_t *fmt)
{
	int k, c, p;

	c = p = -1;
	while ((k = fgetc(inFile)) != EOF) {
		if (k == '\n') {
			if (fmt->putTagEOL(outFile))
				c = -1;
		} else if (k == 0xff) {
			/* Location title mode */
			if (p != -1 && (!fmt->supBackColor || p != optBackColor))
				fmt->putTagEnd(outFile);

			c = p = -2;
			
			fmt->putTagStart(outFile, -1);
			
			while ((k = fgetc(inFile)) != EOF) {
				if (k == 0xfe)
					break;
				else
					fprintf(outFile, "%c", k);
			}
		} else {
			c = mcGetColor(k, optUseOldFormat);
			if (c != p) {
				if (p != -1 && (!fmt->supBackColor || p != optBackColor))
					fmt->putTagEnd(outFile);
				
				if (!fmt->supBackColor || (c != optBackColor))
					fmt->putTagStart(outFile, c);
				
				fprintf(outFile, "%c", k);
			} else {
				fprintf(outFile, "%c", k);
			}
		}
		
		p = c;
	}
	
	if (p != -1 && (!fmt->supBackColor || p != optBackColor))
		fmt->putTagEnd(outFile);
}


/* Get a symbol
 */
char getSymbol(int i, BOOL useOld)
{
	if (useOld)
		return mapPieces[i].oldSymbol;
	else
		return mapPieces[i].symbol;
}


/* Process a diff
 */
BOOL processDiff(FILE *inFile, FILE *outFile, outfmt_t *fmt)
{
	int c, p;
	size_t offs;

	offs = 0;
	c = p = -1;
	while ((c = fgetc(inFile)) != EOF) {
		if (c == 0xff) {
			if (fmt->putTagEOL(outFile))
				c = -1;
		} else {
			if (c != p) {
				if (p != -1)
					fmt->putTagEnd(outFile);
	
				if (c >= 0) {
					int t = (c / 64),
					q = mcGetColor(c % 64, optUseOldFormat);
					
					if (t > 0) {
						/* FIXME FIXME TODO */
						fprintf(outFile,
						"<i style='background:%s;color:black'>",
						mapColors[q].css);
					} else
						fmt->putTagStart(outFile, q);
					
					fprintf(outFile, "%c",
						getSymbol(q, optUseOldFormat));
				}
			} else if (c >= 0) {
				fprintf(outFile, "%c",
					getSymbol(c % 64, optUseOldFormat));
			} else {
				THERR("Broken map diff input at offset %d.\n", offs);
				exit(15);
			}
		}
		
		p = c;
		offs++;
	}

	if (p != -1) fmt->putTagEnd(outFile);
	
	return TRUE;
}


/* List of output formats
 */
outfmt_t outputFormats[] = {
	{ "xhtml", "XHTML+CSS", TRUE,
	putTagStartXHTML, putTagEndXHTML, putEOLXHTML,
	putFileStartXHTML, putFileEndXHTML
	},

	{ "html", "Old HTML without CSS", TRUE,
	putTagStartHTML, putTagEndHTML, putEOLHTML,
	putFileStartHTML, putFileEndHTML
	},

	{ "ansi", "ANSI text", FALSE,
	putTagStartANSI, putTagEndANSI, putEOLANSI,
	putFileStartANSI, putFileEndANSI
	},

	{ "text", "Plain ASCII text", FALSE,
	putTagStartText, putTagEndText, putEOLText,
	putFileStartText, putFileEndText
	},
};

const int noutputFormats = (sizeof(outputFormats) / sizeof(outfmt_t));


void argShowHelp(void)
{
	int i;
	
	th_args_help(stderr, optList, optListN, th_prog_name,
	"[options] <input mapfile>");
	
	fprintf(stderr, "\nAvailable OUTPUT formats:\n");
	for (i = 0; i < noutputFormats; i++) {
		fprintf(stderr, "  %-8s - %s %s\n",
		outputFormats[i].fmtName,
		outputFormats[i].fmtDescription,
		(i == optOutputFormat) ? "(default)" : ""
		);
	}

	fprintf(stderr, "\n");
}


BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
{
	int i, n;
	
	switch (optN) {
	case 0:
		argShowHelp();
		exit(0);
		break;

	case 1:
		th_verbosityLevel++;
		break;
	
	case 2:
		th_verbosityLevel = -1;
		break;
	
	case 3:
		optXHTMLTagName = optArg;
		THMSG(2, "HTML tag set to '%s'\n", optXHTMLTagName);
		break;
	
	case 4:
		optPerformAnalysis = TRUE;
		THMSG(2, "Analysis enabled.\n");
		break;
	
	case 5:
		optInputIsDiff = TRUE;
		THMSG(2, "Input is a 'diff', handling it as such.\n");
		break;
		
	case 6:
		optUseOldFormat = TRUE;
		THMSG(2, "Input is using old map symbols/colors.\n");
		break;
	
	case 7:
		destFilename = optArg;
		THMSG(2, "Output file set to '%s'.\n", destFilename);
		break;
	
	case 8:
		/* Get format */
		for (i = 0, n = -1; (i < noutputFormats) && (n < 0); i++)
			if (th_strcmp(optArg, outputFormats[i].fmtName) == 0)
				n = i;
		
		if (n < 0) {
			THERR("Invalid output format '%s'\n", optArg);
			return FALSE;
		}
		
		optOutputFormat = n;
		THMSG(2, "Output format set to '%s'\n", optArg);
		break;
	
	case 9:
		optMapTitle = optArg;
		THMSG(2, "Map title string set to '%s'.\n", optMapTitle);
		break;
	
	case 10:
		optCheatMode = TRUE;
		THMSG(2, "HTML cheats mode enabled!\n");
		break;

	default:
		THERR("Unknown option '%s'.\n", currArg);
		return FALSE;
	}
	
	return TRUE;
}


BOOL argHandleFile(char *currArg)
{
	if (!srcFilename)
		srcFilename = currArg;
	else {
		THERR("Too many input map files specified!\n");
		return FALSE;
	}

	return TRUE;
}

#define NMAX 256

/* Main program
 */
int main(int argc, char *argv[])
{
	FILE *inFile, *outFile;
	outfmt_t *fmt = NULL;

	/* Initialize */
	th_init("colormap", "ASCII map colorizer", "0.1", NULL, NULL);
	th_verbosityLevel = 1;
	
	/* Parse arguments */
	if (!th_args_process(argc, argv, optList, optListN,
		argHandleOpt, argHandleFile, TRUE))
		exit(1);
	
	if (srcFilename == NULL) {
		THERR("Nothing to do. (try --help)\n");
		exit(0);
	}
	
	/* Do statistical analysis, if needed */
	if (optPerformAnalysis) {
		int k, c, p, i, tMax, fMax, tn, fn;
		int colChangesTo[NMAX];
		int colChangesFrom[NMAX];
		
		if (optInputIsDiff) {
			THERR("Cannot perform analysis for diff format files, sorry!\n");
			exit(2);
		}
		
		THMSG(1, "Performing statistical frequency analysis ...\n");
		
		THMSG(2, "Reading '%s' for analysis data ...\n",
			srcFilename);

		if ((inFile = fopen(srcFilename, "rb")) == NULL) {
			THERR("Error opening input file '%s'!\n",
				srcFilename);
			exit(1);
		}
		
		/* Initialize counters */
		th_memset(colChangesTo, 0, sizeof(colChangesTo));
		th_memset(colChangesFrom, 0, sizeof(colChangesFrom));
		
		/* Read data, keeping statistics of colour change frequencies
		 */
		c = p = -1;
		while ((k = fgetc(inFile)) != EOF) {
			if (k != '\n' && k != ' ' && k < 0xfe) {
				c = mcGetColor(k, optUseOldFormat);
				if ((c != p) && (c >= 0) && (c < NMAX)) {
					colChangesTo[c]++;
					
					if ((p >= 0) && (p < NMAX))
						colChangesFrom[p]++;
				}
			}
			p = c;
		}
		
		fclose(inFile);
		
		/* Find highest frequency
		 */
		THMSG(2, "Computing results.\n");
		
		tMax = fMax = tn = fn = -1;
		for (i = 0; i < NMAX; i++) {
			if (colChangesTo[i] > tMax) {
				tMax = colChangesTo[i];
				tn = i;
			}
			if (colChangesFrom[i] > fMax) {
				fMax = colChangesFrom[i];
				fn = i;
			}
		}
		
		THMSG(2, "tMax=%d, tn=%d -- fMax=%d, fn=%d\n",
			tMax, tn, fMax, fn);

		if (tMax > fMax)
			optBackColor = tn;
		else
			optBackColor = fn;
		
		THMSG(1, "Using colour %d as 'background' color.\n",
			optBackColor);
	}
	
	/* Open input file */
	if ((inFile = fopen(srcFilename, "rb")) == NULL) {
		THERR("Error opening input file '%s'!\n",
			srcFilename);
		exit(1);
	}
	
	/* Open output file */
	if (destFilename == NULL)
		outFile = stdout;
	else if ((outFile = fopen(destFilename, "wb")) == NULL) {
		THERR("Error opening output file '%s'!\n",
			destFilename);
		exit(1);
	}

	/* Okay, let's process the shit */
	fmt = &outputFormats[optOutputFormat];
	THMSG(1, "Converting to '%s' ...\n", fmt->fmtName);

	fmt->putFileStart(outFile);

	if (optInputIsDiff)
		processDiff(inFile, outFile, fmt);
	else
		processNormal(inFile, outFile, fmt);

	fmt->putFileEnd(outFile);

	fclose(outFile);
	fclose(inFile);
	
	THMSG(1, "Done.\n");
	
	exit(0);
	return 0;
}