/*-
 * Copyright (c) 2000
 * Tatsuya Kudoh(CDR/TK),ROYALPANDA.    All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include<stdio.h>

#define STATE_NORMAL		0
#define STATE_COMMENT_START	1
#define STATE_COMMENT		2
#define STATE_COMMENT_END	3
#define STATE_STRING		4

typedef struct{
	int width;
	int height;
	int color[128];
}form_t;


static int State = STATE_NORMAL;
static FILE *Cur_fp;
static int End_of_file;

static void init_parse( FILE *fp )
{
	Cur_fp = fp;
	State = STATE_NORMAL;
	End_of_file = 0;
}


static int read_char( void )
{
	int c;

	while( (c = fgetc(Cur_fp)) != EOF ){
		switch( State ){
		case STATE_NORMAL:
			if( c == '/' )
				State = STATE_COMMENT_START;
			else if( c == '"' )
				State = STATE_STRING;
			else if( c == ',' )
				return 0;
			break;

		case STATE_COMMENT_START:
			if( c == '*' )
				State = STATE_COMMENT;
			else{
				ungetc(c,Cur_fp);
				State = STATE_NORMAL;
			}
			break;

		case STATE_COMMENT:
			if( c == '*' )
				State = STATE_COMMENT_END;
			break;

		case STATE_COMMENT_END:
			if( c == '/' )
				State = STATE_NORMAL;
			else if( c != '*' )
				State = STATE_COMMENT;
			break;

		case STATE_STRING:
			if( c == '"' )
				State = STATE_NORMAL;
			else
				return c;
			break;
		}
	}
	return EOF;
}


static int read_string( char *buf, int bufsiz )
{
	int len,c;

	if( End_of_file )
		return -1;

	len = 0;
	bufsiz--;

	while( len < bufsiz ){
		c = read_char();
		if( c == 0 )
			break;
		if( c == EOF ){
			End_of_file = 1;
			break;
		}

		*buf++ = c;
		len++;
	}
	*buf = '\0';
	return len;
}


static int cmp( char *p, int plen, char *q, int qlen )
{
	int len;

	len = plen < qlen ? plen : qlen;

	p += plen;
	q += qlen;

	while( len-- ){
		p--;
		q--;
		if( tolower(*p) != tolower(*q) )
			return 0;
	}
	return 1;
}


static int parse_format( form_t *p )
{
	char buf[1024];
	char *s;
	int i;
	int ncols,cpp;
	int len;

	if( read_string(buf,1024) < 0 )
		return -1;
	if( sscanf(buf,"%d %d %d %d",&p->width,&p->height,&ncols,&cpp) < 4 )
		return -1;
	if( p->width < 1 || p->height < 1 )
		return -1;
	if( cpp != 1 )
		return -1;

	p->width = (p->width + 7) & ~7;
	p->height = (p->height + 7) & ~7;

	for( i = 0 ; i < 128 ; i++ )
		p->color[i] = 2;

	while( ncols-- ){
		if( (len = read_string(buf,1024)) < 0 )
			return -1;
		if( cmp(buf,len,"none",4) )
			p->color[buf[0] & 127] = 0;
		else if( cmp(buf,len,"black",5) )
			p->color[buf[0] & 127] = 1;
		else if( cmp(buf,len,"white",5) )
			p->color[buf[0] & 127] = 3;
	}
	return 0;
}


static unsigned char *create_image( form_t *p )
{
	int x,y;
	int c;
	unsigned char *image,*img,*ip;

	image = (unsigned char*)malloc(p->width * p->height);
	if( image == NULL )
		return NULL;

	memset(image,0,p->width*p->height);

	img = image;
	for( y = 0 ; y < p->height ; y++ ){
		ip = img;
		img += p->width;
		x = 0;
		while( (c = read_char()) != 0 ){
			if( c == EOF )
				return image;
			if( x < p->width ){
				*ip++ = p->color[c & 127];
				x++;
			}
		}
	}
	return image;
}


static void print_block( unsigned char *p, int pixel_per_line )
{
	int bits;
	int x,y;

	for( y = 0 ; y < 8 ; y++ ){
		bits = 0;
		for( x = 0 ; x < 8 ; x++ ){
			bits <<= 1;
			bits |= (*p & 2) << 7 | (*p & 1);
			p++;
		}
		printf("0x%04x,",bits);
		p += pixel_per_line - 8;
	}
}


static void print_block_turn( unsigned char *p, int pixel_per_line )
{
	int bits;
	int x,y;

	p += pixel_per_line * 8;
	for( y = 0 ; y < 8 ; y++ ){
		bits = 0;
		for( x = 0 ; x < 8 ; x++ ){
			p -= pixel_per_line;
			bits <<= 1;
			bits |= (*p & 2) << 7 | (*p & 1);
		}
		printf("0x%04x,",bits);
		p += pixel_per_line * 8 + 1;
	}
}


static void print_all_block( unsigned char *p, form_t *f, int turn )
{
	int x,y;
	unsigned char *pp;

	for( y = 0 ; y < f->height ; y += 8 ){
		pp = p;
		p += f->width * 8;
		for( x = 0 ; x < f->width ; x += 8 ){
			if( turn )
				print_block_turn(pp,f->width);
			else	
				print_block(pp,f->width);
			printf(" /* %2d,%2d */\n",x/8,y/8);
			pp += 8;
		}
	}
}


static int convert( char *file,int turn )
{
	FILE *fp;

	unsigned char *p;
	form_t f;
	int x,y;

	if( file == NULL ){
		fp = stdin;
		file = "(stdin)";
	}else{
		fp = fopen(file,"r");
		if( fp == NULL ){
			fprintf(stderr,"cannot open '%s'\n",file);
			return -1;
		}
	}

	init_parse(fp);
	if( parse_format(&f) < 0 ){
		fprintf(stderr,"%s: Unsupported Pixmap format\n",file);
		if( fp != stdin )
			fclose(fp);
		return -1;
	}
	p = create_image(&f);
	if( p == NULL ){
		fprintf(stderr,"Out of memory\n");
		exit(1);
	}
	print_all_block(p,&f,turn);

	if( fp != stdin )
		fclose(fp);
	return 0;
}


int main( int argc, char **argv )
{
	int turn;
	int err;

	argc--;
	argv++;

	if( argc > 0 && strcmp(*argv,"-turn") == 0 ){
		argc--;
		argv++;
		turn = 1;
	}else{
		turn = 0;
	}

	err = 0;

	if( argc > 0 ){
		while( argc-- ){
			printf("\t/* %s */\n",*argv);
			if( convert(*argv,turn) < 0 )
				err = 1;
			argv++;
		}
	}else{
		if( convert(NULL,turn) < 0 )
			err = 1;
	}
	return err;
}
