#define	KERNING_AVAILABLE	0x0268
#define	X_WIDTHS_AVAILABLE	0x0068
#define	AMIGA_STANDARD		0x0101
#define	FONT_SPECIFIC		0x0100

ULONG WriteMetricsVector(char *afmFilename, int typeWeight)

/* This function is the heart of ConvertAFM. It creates what I
   call a "Metrics Vector"; a complete .metric structure with all
   typeface information, character widths, and kerning tables.

   It creates a file in T: named by the AFM's typeface name. 
   It contains the complete metrics vector except for the
   typeface style, which you must supply in typeWeight. It
   also returns the length of the file. */

{
static	WORD		kerningTables[256][256];
static	char		kerningCheckList[16384];
static	char		currentList[256],*kerningArray,*incomingString,headerCheck[26],encodingScheme[20],intString[4][20],metricFilename[26],typefaceName[68],*intChars;
static	WORD		metricInfo[18],xWidths[256],kerningPointers[256];
static	FILE		*afmFile,*metricFile;
static	int		test,test2,test3,test4,test5,asciiCode,asciiCode2,xWidth,kerningArrayLength,currentOffset;
static	ULONG		vectorLength;
static	UWORD		index,index2;
static	BOOL		goodfit;

	for (index=0;index<18;index++)
		metricInfo[index]=0;
	for(index=0;index<68;index++)
		typefaceName[index]=0;
	metricInfo[0]=X_WIDTHS_AVAILABLE;
	for (index=0;index<256;index++)
		xWidths[index]=0;

	afmFile=fopen(afmFilename,"r");

	if (afmFile==0)
	{
		fclose(afmFile);
		return(0);
	}

/* If the AFM file didn't exist, it returns a vectorLength
   of zero. Logical, yes? A non-existant file with zero length? */

	headerCheck[0]=0;
	test=-1;
	while(test!=0)
	{
		incomingString=freadline(afmFile);
		sscanf(incomingString,"%s\n",headerCheck);
		test=strcmp(headerCheck,"FontName");
	}
	sscanf(incomingString,"%s %s",headerCheck,typefaceName);

	test=-1;
	while(test!=0)
	{
		incomingString=freadline(afmFile);
		sscanf(incomingString,"%s ",headerCheck);
		test=strcmp(headerCheck,"EncodingScheme");
	}
	sscanf(incomingString,"%s %s",headerCheck,encodingScheme);
	test=strcmp(encodingScheme,"FontSpecific");
	test2=strcmp(encodingScheme,"AppleStandard");
	if (test==0 || test2==0)
		metricInfo[6]=FONT_SPECIFIC;
	else
		metricInfo[6]=AMIGA_STANDARD;
	fsetpos(afmFile,0);

/* I gotta do this for every parameter I require! Ugh! */

	test=-1;
	while(test!=0)
	{
		incomingString=freadline(afmFile);
		sscanf(incomingString,"%s ",headerCheck);
		test=strcmp(headerCheck,"UnderlinePosition");
	}
	sscanf(incomingString,"%s %s",headerCheck,intString[0]);
	metricInfo[11]=atoi(intString[0]);

	test=-1;
	while(test!=0)
	{
		incomingString=freadline(afmFile);
		sscanf(incomingString,"%s ",headerCheck);
		test=strcmp(headerCheck,"UnderlineThickness");
	}
	sscanf(incomingString,"%s %s",headerCheck,intString[0]);
	metricInfo[12]=atoi(intString[0]);

	test=-1;
	while(test!=0)
	{
		incomingString=freadline(afmFile);
		sscanf(incomingString,"%s ",headerCheck);
		test=strcmp(headerCheck,"FontBBox");
	}
	sscanf(incomingString,"%s %s %s %s %s",headerCheck,intString[0],intString[1],intString[2],intString[3]);
	for (index=0;index<4;index++)
		metricInfo[index+7]=atoi(intString[index]);

/* Some typefaces won't have letter-like qualities, like
   cap height, x-height, etc. So, if the very next line is
   "StartCharMetrics", then it creates these values based
   on the Font Bounding Box. */

	test=-1;
	incomingString=freadline(afmFile);
	sscanf(incomingString,"%s ",headerCheck);
	test=strcmp(headerCheck,"StartCharMetrics");

	if (test!=0)
	{
		test2=-1;
		while(test2!=0)
		{
			sscanf(incomingString,"%s ",headerCheck);
			test2=strcmp(headerCheck,"CapHeight");
		}
		sscanf(incomingString,"%s %s",headerCheck,intString[0]);
		metricInfo[13]=atoi(intString[0]);
	
		test2=-1;
		while(test2==0)
		{
			incomingString=freadline(afmFile);
			sscanf(incomingString,"%s ",headerCheck);
			test2=strcmp(headerCheck,"XHeight");
		}
		sscanf(incomingString,"%s %s",headerCheck,intString[0]);
		metricInfo[14]=atoi(intString[0]);
	
		test2=-1;
		while(test2!=0)
		{
			incomingString=freadline(afmFile);
			sscanf(incomingString,"%s ",headerCheck);
			test2=strcmp(headerCheck,"Descender");
		}
		sscanf(incomingString,"%s %s",headerCheck,intString[0]);
		metricInfo[16]=atoi(intString[0]);
	
		test2=-1;
		while(test2!=0)
		{
			incomingString=freadline(afmFile);
			sscanf(incomingString,"%s ",headerCheck);
			test2=strcmp(headerCheck,"Ascender");
		}
		sscanf(incomingString,"%s %s",headerCheck,intString[0]);
		metricInfo[15]=atoi(intString[0]);

		incomingString=freadline(afmFile);
		sscanf(incomingString,"%s %s",headerCheck,intString[0]);

	}
	else
	{
		for (index=13;index<17;index++)
			metricInfo[index]=0;
		sscanf(incomingString,"%s %s",headerCheck,intString[0]);
		metricInfo[16]=metricInfo[8];
		for (index=13;index<16;index++)
			metricInfo[index]=metricInfo[8]+metricInfo[10];
	}

	metricInfo[17]=typeWeight;
	
/* By now we're on the very first line of x-widths. 
   We start by comparing all the chars to either Amiga Standard
   or Apple Standard encoding and arrange the X-widths in an
   ASCII format. The check arrays #included are used for this.
   If the typeface has Font Specific encoding the ASCII values
   are used directly. */

	vectorLength=104;
	if (metricInfo[6]==FONT_SPECIFIC)
	{
		test2=-1;
		incomingString=freadline(afmFile);
		while (test2!=0)
		{
			sscanf(incomingString,"C %s ; WX %s ",intString[0],intString[1]);
			asciiCode=atoi(intString[0]);
			if (asciiCode!=-1)
				xWidths[asciiCode]=atoi(intString[1]);
			
			incomingString=freadline(afmFile);
			test2=strcmp(incomingString,"EndCharMetrics");
		}
		vectorLength=vectorLength+256*2;
	}
	else
	{
		test2=-1;
		incomingString=freadline(afmFile);
		while (test2!=0)
		{
			sscanf(incomingString,"C %s ; WX %s ; N %s ",intString[0],intString[1],intString[2]);
			index=0;asciiCode=-1;
			while (asciiCode==-1 && index<256)
			{
				test=strcmp(amigaEncoding[index],intString[2]);
				if (test==0)
					asciiCode=index;
				else
					index=index+1;
			}
			if (asciiCode!=-1)
				xWidths[asciiCode]=atoi(intString[1]);

			incomingString=freadline(afmFile);
			test2=strcmp(incomingString,"EndCharMetrics");
		}
		vectorLength=vectorLength+256*2;
	}

/* If this is any type of standard encoding, I look for kerning
   tables. This means AdobeStandard, AppleStandard, or whatever.

   NOTE: Font Specific encoded typefaces CANNOT have kerning
   tables or this program will ignore them. To add kerning to
   a font specific encoded typeface, you'll have to wait for
   my kerning pair editor to be released. 

   Anyway, on to kerning pair decyphering. */

	test=-1;test2=-1;
	while (test!=0 && test2!=0)
	{
		incomingString=freadline(afmFile);
		test=strcmp(incomingString,"StartKernData");
		test2=strcmp(incomingString,"EndFontMetrics");
	}
	test2=strcmp(encodingScheme,"FontSpecific");
	if (test==0 && test2!=0)
	{

		for (index=0;index<256;index++)
			for (index2=0;index2<256;index2++)
				kerningTables[index][index2]=0;

		test3=-1;
		while (test3!=0)
		{
			incomingString=freadline(afmFile);
			sscanf(incomingString,"%s ",headerCheck);
			test3=strcmp(headerCheck,"StartKernPairs");
		}
		test3=-1;
		incomingString=freadline(afmFile);
		test=strcmp(incomingString,"EndKernPairs");
		while (test3!=0)
		{
			sscanf(incomingString,"%s ",headerCheck);
			test4=strcmp(headerCheck,"KPX");
			if (test4==0)
			{
				sscanf(incomingString,"KPX %s %s %s",intString[0],intString[1],intString[2]);
				index=0;asciiCode=-1;
				while (asciiCode==-1 && index<256)
				{
					test5=strcmp(amigaEncoding[index],intString[0]);
					if (test5==0)
						asciiCode=index;
					else
						index=index+1;
				}
				index=0;asciiCode2=-1;
				while (asciiCode2==-1 && index<256)
				{
					test5=strcmp(amigaEncoding[index],intString[1]);
					if (test5==0)
						asciiCode2=index;
					else
						index=index+1;
				}
				kerningTables[asciiCode][asciiCode2]=atoi(intString[2]);
			}
			incomingString=freadline(afmFile);
			test3=strcmp(incomingString,"EndKernPairs");
		}
		for (index=0;index<256;index++)
			for (index2=0;index2<256;index2++)
				if (kerningTables[index][index2]!=0)
				{
					kerningPointers[index]=256;
					index2=256;
				}
				else
					kerningPointers[index]=0;

/* Since making a separate function for encoding the kerning
   array doesn't work with DICE (UGH!) I have to include it
   here. */

		for (index=0;index<16384;index++)
			kerningCheckList[index]=32;
		/* kerningCheckList nulled to spaces. */
	
		kerningArrayLength=256;

		for (index=0;index<256;index++)
		{
			if (kerningPointers[index]!=0)
			{
				for (index2=0;index2<256;index2++)
				{
					if (kerningTables[index][index2]!=0)
						currentList[index2]=index;
					else
						currentList[index2]=32;
				}
				/* CurrentList created. */
				goodfit=TRUE;currentOffset=0;
				for (index2=0;index2<256;index2++)
				{
					if (currentList[index2]!=32 && kerningCheckList[index2]!=32)
					{
						goodfit=FALSE;
						index2=256;
					}
				}
				while (goodfit==FALSE)
				{
					currentOffset=currentOffset+1;
					for (index2=0;index2<256;index2++)
					{
						if (currentList[index2]!=32 && kerningCheckList[index2+currentOffset]!=32)
						{
							goodfit=FALSE;
							index2=256;
						}
						else
							goodfit=TRUE;
					}
				}

/* A good fit was found. Record the offset and insert
   into the check array. */

				for (index2=0;index2<256;index2++)
					if (currentList[index2]!=32)
						kerningCheckList[index2+currentOffset]=currentList[index2];

				kerningPointers[index]=kerningPointers[index]+currentOffset;
				if (kerningArrayLength < currentOffset+256)
					kerningArrayLength=kerningArrayLength+(currentOffset+256-kerningArrayLength);
			}
/* NEXT! */
		}
		for (index=0;index<256;index++)
			if (kerningPointers[index]!=0)
			{
				vectorLength=vectorLength+256*4+kerningArrayLength*4;
				metricInfo[2]=KERNING_AVAILABLE;
				index=256;
			}
		
	}

	fclose(afmFile);

	strcpy(metricFilename,"T:");
	strcat(metricFilename,typefaceName);
	metricFile=fopen(metricFilename,"w");

	for (index=0;index<68;index++)
		fputc(typefaceName[index],metricFile);

	for (index=0;index<18;index++)
	{
		intChars=&metricInfo[index];
		fprintf(metricFile,"%c%c",intChars[0],intChars[1]);
	}

	for (index=0;index<256;index++)
	{
		intChars=&xWidths[index];
		fprintf(metricFile,"%c%c",intChars[0],intChars[1]);
	}

 	if (metricInfo[2]==KERNING_AVAILABLE)
	{
		for (index=0;index<256;index++)
			if (kerningPointers[index]!=0)
			{
				intChars=&kerningPointers[index];
				fprintf(metricFile,"%c%c%c%c",intChars[0],intChars[1],0,index);
			}
			else
				fprintf(metricFile,"%c%c%c%c",0,0,0,0);

		for (index=0;index<kerningArrayLength;index++)
			if (kerningCheckList[index]!=32)
			{
				asciiCode=kerningCheckList[index];
				asciiCode2=index-kerningPointers[asciiCode]+256;
				intChars=&kerningTables[asciiCode][asciiCode2];
				fprintf(metricFile,"%c%c%c%c",intChars[0],intChars[1],0,asciiCode);
			}
			else
				fprintf(metricFile,"%c%c%c%c",0,0,0,0);

/* Cheaky way of writing the kerning table, eh? :-) */

	}

	fclose(metricFile);
	return(vectorLength);

};
