
/*
 * cclibToBdf:	convert CCLIB font library (CC-DOS) to XV11R3 BDF font.
 *
 * Yongguang ZHANG [5/12/1989]
 */

#include <stdio.h>
#include <strings.h>
#define NULL	0

char *strtok();


#define QuLength	94	/* number of hanzi in one Qu 16..87 */
#define DefaultSize	16	/* 16x16 */

FILE *inF, *inpF, *ouF;
unsigned int sizeX;
unsigned int sizeY;
unsigned int DefaultChar;

/* the list of Qu appear in cclib, appearing in their order, 255 at most */
unsigned short QuOrders[256];
unsigned short NumberOfQu = 0;

main( argc, argv )
	int argc ;
	char * argv[] ;
{
 char fileName[ 1024 ] ;
 register int n ;
 char *fontname = NULL;
 extern FILE *fopen();


	if ((argc != 2) && (argc != 3) ) {
		usage( argv[0] );
	}

	strcpy( fileName, argv[1] );
	inF = fopen( fileName, "r" );
	if ( ! inF ) {
		perror( fileName );
		exit( 1 );
	}
	strcat( fileName, ".pf" );
	inpF = fopen( fileName, "r" );	/* try open .pf file */
	if (! inpF) {
		/* no parameter file, use default value */
		register int i = 0;

		sizeX = DefaultSize;
		sizeY = DefaultSize;
		for ( n = 1 ; n <= 9 ; n++ )	/* Qu: 1-9 */
			QuOrders[i++] = n;
		for ( n = 16 ; n <= 87 ; n++ )	/* Qu: 16-87 */
			QuOrders[i++] = n;
		NumberOfQu = i;
		DefaultChar = 0xd7fa;	/* space: GB=d7fa, QW=(55,90) */
	} else {
		/* parse the .pf file */
		char buf[256];
		char *p = buf;
		register int i = 0;

		if (! fgets(buf, 256, inpF))
			WrongFileFormat( fileName );
		if (sscanf( buf, "%d", &sizeX ) != 1 )
			WrongFileFormat( fileName );
		
		if (! fgets(buf, 256, inpF))
			WrongFileFormat( fileName );
		if ( sscanf( buf, "%d", &sizeY ) != 1 )
			WrongFileFormat( fileName );

		if (! fgets(buf, 256, inpF) )
			WrongFileFormat( fileName );
		if ( sscanf( buf, "%x", &DefaultChar ) != 1 )
			WrongFileFormat( fileName );

		if (! fgets(buf, 256, inpF) )
			WrongFileFormat( fileName );
		if ( !(p =  strtok( buf, ", \t\n#" )) )
			WrongFileFormat( fileName );
		while ( 1 ) {
			int x, y;

			if ( sscanf( p, "%d-%d", &x, &y ) == 2 ) {
				if ( x >= y )
					WrongFileFormat( fileName );
				while ( x <= y )
					QuOrders[i++] = x++;
				p = strtok( NULL, ", \t\n#" );
				continue;
			}
			if ( sscanf( p, "%d", &x ) == 1 ) {
				QuOrders[i++] = x;
				p = strtok( NULL, ", \t\n#" );
				continue;
			}

			/* matching fail */
			NumberOfQu = i;
			break;
		}
	}
	fontname = rindex(argv[1], '/');
	if (fontname == (char *)0 )
		fontname = argv[1];
	else
		fontname++ ;
	if (argc == 2)
		ouF = stdout;
	else {
		register int l;

		strcpy( fileName, argv[2] );
		l = strlen(fileName);
		if ( (l <= 4) || ( strcmp( fileName + l - 4, ".bdf" ) != 0 ) )
			strcat( fileName, ".bdf" );
		ouF = fopen( fileName, "w" );
		if ( ! ouF ) {
			perror( fileName );
			exit( 1 );
		}
	}

	fprintf( ouF, "STARTFONT 2.1\n" );
	fprintf( ouF, "COMMENT\n" );
	fprintf( ouF, "COMMENT   %ux%u Chinese Character set.\n", sizeX, sizeY );
	fprintf( ouF, "COMMENT   National Standard GB2312-80 of People's Republic of China\n" );
	fprintf( ouF, "COMMENT\n" );
	fprintf( ouF, "COMMENT   Contributor: Institute of Software, Academia Sinica\n" );
	fprintf( ouF, "COMMENT\n" );
	fprintf( ouF, "FONT %s\n", fontname );
	fprintf( ouF, "SIZE %u 80 80\n", sizeX );
	fprintf( ouF, "FONTBOUNDINGBOX %u %u 0 0\n", sizeX, sizeY + 2 );
	fprintf( ouF, "STARTPROPERTIES 8\n");
	fprintf( ouF, "COMMENT ****** LogicalFontDescription Begin\n" );
	fprintf( ouF, "FONTNAME_REGISTRY \"\"\n" );
	fprintf( ouF, "FAMILY_NAME \"Chinese Character\"\n" );
	fprintf( ouF, "FOUNDRY \"ISAS\"\n" );
	fprintf( ouF, "CHARSET_REGISTRY \"GB2312-80\"\n" );
	fprintf( ouF, "COPYRIGHT \"Public domain Chinese Character font, share and enjor\"\n");
	fprintf( ouF, "FONT_ASCENT %u\n", sizeX );
	fprintf( ouF, "FONT_DESCENT 0\n" );
	fprintf( ouF, "DEFAULT_CHAR %d\n", DefaultChar );
	fprintf( ouF, "COMMENT ****** LogicalFontDescription End\n" );
	fprintf( ouF, "ENDPROPERTIES\n");

	/* 9 Qu of special symbols before Hanzi */
	fprintf( ouF, "CHARS %d\n", NumberOfQu * QuLength );

	for ( n=0 ; n < NumberOfQu ; n++ )
		OutputQu( QuOrders[n] );
	fprintf( ouF, "ENDFONT\n" );
}

/********************/

typedef unsigned char CARD8 ;
typedef unsigned short CARD16 ;

typedef union GBCODE {
	CARD8	b[2] ;
	CARD16	s ;
} GBcode, *PtrGBcode ;

GBcode nowGB ;

static void
QWtoGB( qu, wei )
	int qu, wei ;
/* QWtoGB -- given integer Qu & Wei,
 *		convert it to the corresponding 2-byte GB-code
 */
{
	nowGB.b[0] = qu  + 0xa0 ; /* + 0x20 | 0x80 */
	nowGB.b[1] = wei + 0xa0 ;
}

/********************/

OutputQu( quNumber )
	int quNumber ;
{
 register int i, j, wei ;
 unsigned char byte;

	for ( wei = 1 ; wei <= QuLength ; wei++ ) {
		QWtoGB( quNumber, wei );
		fprintf( ouF, "STARTCHAR hanzi%d_%d\n",	quNumber, wei );
		fprintf( ouF, "ENCODING %d\n", nowGB.s );
		fprintf( ouF, "SWIDTH 461 0\n" );
		fprintf( ouF, "DWIDTH %u 0\n", sizeX );
		fprintf( ouF, "BBX %u %u 0 0\n", sizeX, sizeY );
		fprintf( ouF, "BITMAP\n" );
		for ( i = sizeY ; i-- ; ) {
			for ( j = (sizeX-1)/8 + 1 ; j-- ; ) {
				fscanf( inF, "%c", &byte );
				fprintf( ouF, "%.2x", byte );
			}
			fprintf( ouF, "\n" );
		}
		fprintf( ouF, "ENDCHAR\n" );
	}
}

usage(program)
  char *program;
{
	fprintf( stderr, "usage: %s inFile [outFile]\n", program );
	exit( -1 );
}

WrongFileFormat(file)
  char *file;
{
	fprintf(stderr,"Wrong file format: %s\n", file );
	exit( -2 );
}


/********************************************************************/
/********************************************************************/

/*LINTLIBRARY*/
/*
 * Return ptr to first occurance of any character from `brkset'
 * in the character string `string'; NULL if none exists.
 */

char *
strpbrk(string, brkset)
register char *string, *brkset;
{
	register char *p;

	do {
		for(p=brkset; *p != '\0' && *p != *string; ++p)
			;
		if(*p != '\0')
			return(string);
	}
	while(*string++);
	return(NULL);
}

/*LINTLIBRARY*/
/*
 * Return the number of characters in the maximum leading segment
 * of string which consists solely of characters from charset.
 */
int
strspn(string, charset)
char	*string;
register char	*charset;
{
	register char *p, *q;

	for(q=string; *q != '\0'; ++q) {
		for(p=charset; *p != '\0' && *p != *q; ++p)
			;
		if(*p == '\0')
			break;
	}
	return(q-string);
}

/*LINTLIBRARY*/
/*
 * uses strpbrk and strspn to break string into tokens on
 * sequentially subsequent calls.  returns NULL when no
 * non-separator characters remain.
 * `subsequent' calls are calls with first argument NULL.
 */

char *
strtok(string, sepset)
char	*string, *sepset;
{
	register char	*p, *q, *r;
	static char	*savept;

	/*first or subsequent call*/
	p = (string == NULL)? savept: string;

	if(p == 0)		/* return if no tokens remaining */
		return(NULL);

	q = p + strspn(p, sepset);	/* skip leading separators */

	if(*q == '\0')		/* return if no tokens remaining */
		return(NULL);

	if((r = strpbrk(q, sepset)) == NULL)	/* move past token */
		savept = 0;	/* indicate this is last token */
	else {
		*r = '\0';
		savept = ++r;
	}
	return(q);
}
