/** 	obsolete.c -  to convert obsolete type records to the C7 format
 *
 */

#include "compact.h"



#define 	getbyte(type)		((uchar) *type++)
#define 	getword(type)		(*((short *)type)++)
#define		getindex(type)		((getbyte(type) == 0x83) ? getword(type) : -1)

LOCAL uchar    *AllocNewStr (TENTRY *OldEntry, ushort length);
LOCAL ushort	MergeLists (ushort, ushort, ushort);
LOCAL void		C6CnvtArgList (ushort, ushort);

// These functions are called through the C6ConvertTypeFcn table
LOCAL void C6CnvtPtrType (TENTRY *OldEntry);
LOCAL void C6CnvtBasePtrType (TENTRY *OldEntry);
LOCAL void C6CnvtStructType (TENTRY *OldEntry);
LOCAL void C6CnvtArrayType (TENTRY *OldEntry);
LOCAL void C6CnvtProcType (TENTRY *OldEntry);
LOCAL void C6CnvtNilType (TENTRY *OldEntry);
LOCAL void C6CnvtBitfieldType (TENTRY *OldEntry);
LOCAL void C6CnvtLabelType (TENTRY *OldEntry);
LOCAL void C6CnvtNotTranType (TENTRY *OldEntry);
LOCAL void C6CnvtFString (TENTRY *OldEntry);
LOCAL void C6CnvtBArrayType (TENTRY *OldEntry);
LOCAL void C6CnvtCobTypeRef (TENTRY *OldEntry);
LOCAL void C6CnvtCobol (TENTRY *OldEntry);

extern ushort AddNewSymbols;
extern char ptr32;

typedef struct {
	uchar				oldtyp;			// Old C6 Symbol record type
	void				(*pfcn) (TENTRY *OldEntry);
} converttypefcn;

converttypefcn	C6ConvertTypeFcn[] = {
	{OLF_POINTER,			C6CnvtPtrType},
	{OLF_BASEPTR,			C6CnvtBasePtrType},
	{OLF_STRUCTURE, 		C6CnvtStructType},
	{OLF_ARRAY, 			C6CnvtArrayType},
	{OLF_PROCEDURE,			C6CnvtProcType},
	{OLF_NIL,				C6CnvtNilType},
	{OLF_BITFIELD,			C6CnvtBitfieldType},
	{OLF_LABEL, 			C6CnvtLabelType},
	{OLF_FSTRING,			C6CnvtFString},
	{OLF_FARRIDX,			C6CnvtNotTranType},
	{OLF_BARRAY,			C6CnvtBArrayType},
	{OLF_COBOLTYPEREF,		C6CnvtCobTypeRef},
	{OLF_COBOL, 			C6CnvtCobol},
};
#define C6CONVERTTYPECNT (sizeof C6ConvertTypeFcn / sizeof (C6ConvertTypeFcn[0]))


/**
 *
 *	ConvertObsolete
 *
 *	Given the index to a type string, it performs a conversion if the
 *	string represents an obsolete record like the pointer, based
 *	pointer, or structure record.
 *
 */


void ConvertObsolete (ushort OldIndex)
{
	uchar *TypeString;
	TENTRY *OldEntry;
	int 	i;
	uchar type;
	converttypefcn * pTypeFcn;
	CV_typ_t	forward;

	OldEntry = GetTypeEntry (OldIndex, &forward);
	DASSERT(!OldEntry->flags.IsNewFormat);

	TypeString = OldEntry->TypeString; // get the string
	type = TypeString[3];
	for (pTypeFcn = C6ConvertTypeFcn, i = 0; i < C6CONVERTTYPECNT; i++, pTypeFcn++) {
		if (pTypeFcn->oldtyp == type) {
			break;
		}
	}

	if (i != C6CONVERTTYPECNT) {
		pTypeFcn->pfcn (OldEntry);
	}
	else {
		// unexpected C6 type - convert to a nil type
		// sps - 12/2/92
		Warn (WARN_BADTYP, FormatMod (pCurMod), NULL);
		C6CnvtNilType (OldEntry);
	}
}



LOCAL void C6CnvtPtrType (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;
	lfPointer	NewType;
	uchar * 	pchNew;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	int 		i;

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString; // get the string

	// calculate new length
	// M00SPEED - All of these evaluate to constants
	usNTotal = LNGTHSZ + offsetof (lfPointer, pbase);
	usNewLength = usNTotal - LNGTHSZ;

	// Set constant fields
	NewType.leaf = LF_POINTER;
	switch (pchTypeStr[4]) {			// get old model
		case OLF_NEAR :
			NewType.attr.ptrtype = CV_PTR_NEAR;
			break;

		case OLF_FAR :
			NewType.attr.ptrtype = CV_PTR_FAR;
			break;

		case OLF_HUGE :
			NewType.attr.ptrtype = CV_PTR_HUGE;
			break;

		default:
			DASSERT(FALSE);
			break;
	}
	NewType.attr.ptrmode = CV_PTR_MODE_PTR;
	NewType.attr.isvolatile = FALSE;
	NewType.attr.isconst = FALSE;
	NewType.attr.isflat32 = ptr32;
	NewType.attr.unused = 0;

	DASSERT(pchTypeStr[5] == OLF_INDEX);
	NewType.utype = *((ushort *)(pchTypeStr + 6));


	// Just make sure that the string isn't longer than we expect
	DASSERT(usNewLength <= (*((ushort UNALIGNED *)(pchTypeStr + 1)) + 1));

	// Copy the new symbol over the old one
	*((ushort *)(pchTypeStr))++ = usNewLength;
	for (pchNew = (uchar *)&NewType, i = usNTotal - LNGTHSZ; i; i--) {
		*pchTypeStr++ = *pchNew++;
	}

	DASSERT(pchTypeStr == OldEntry->TypeString + usNewLength + LNGTHSZ);
}




LOCAL void C6CnvtBasePtrType (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;
	lfPointer	NewType;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	int 		i;
	ushort		usVarOff = 0;
	uchar		chVarData[MAXSTRLEN+1];
	ushort		usOldLen;			// Length of the old record excluding length and link.
	ushort		usfSymbolBased = FALSE;
	uchar * 	pchSymStr;
	uchar * 	pchSrc;
	uchar * 	pchDest;

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString; // get the string
	usOldLen = *((ushort UNALIGNED *)(pchTypeStr + 1));

	// Set constant fields
	NewType.leaf = LF_POINTER;
	DASSERT(pchTypeStr[4] == OLF_INDEX);
	NewType.utype = *((ushort UNALIGNED *)(pchTypeStr + 5));

	switch (pchTypeStr[7]) {			// get old based type
		case OLF_BASESEG :
			NewType.attr.ptrtype = CV_PTR_BASE_SEG;
			*((ushort *)(chVarData + usVarOff)) = *((ushort *)(pchTypeStr + 8));
			usVarOff += 2;
			break;

		case OLF_BASEVAL :
			NewType.attr.ptrtype = CV_PTR_BASE_VAL;
			usfSymbolBased = TRUE;
			break;

		case OLF_BASESEGVAL :
			NewType.attr.ptrtype = CV_PTR_BASE_SEGVAL;
			usfSymbolBased = TRUE;
			break;

		case OLF_BASEADR :
			NewType.attr.ptrtype = CV_PTR_BASE_ADDR;
			usfSymbolBased = TRUE;
			break;

		case OLF_BASESEGADR :
			NewType.attr.ptrtype = CV_PTR_BASE_SEGADDR;
			usfSymbolBased = TRUE;
			break;

		case OLF_BASETYPE :
			NewType.attr.ptrtype = CV_PTR_BASE_TYPE;
			DASSERT(*((ushort *)(pchTypeStr + 8)) == 0);
			// Change to old T_VOID value, then let cnvtprim convert it
			*((ushort *)chVarData + usVarOff) = 0x80 + 0x1C;
			usVarOff += 2;
			*(chVarData + usVarOff) = 0; // Zero length name
			usVarOff += 1;
			break;

		case OLF_BASESELF :
			NewType.attr.ptrtype = CV_PTR_BASE_SELF;
			break;

		default:
			DASSERT(FALSE);
			break;
	}
	if (usfSymbolBased) {
		// Copy the entire symbol into the type.

		// Get the address of the C6 Symbol string.
		pchSymStr = GetSymString (*((ushort *)(pchTypeStr + 8))); // get sym string

		// Convert the C6 Symbol to a C7 Symbol and put it in the variable data.
		usVarOff += C6CnvtSymbol (chVarData + usVarOff, pchSymStr);
	}

	NewType.attr.ptrmode = CV_PTR_MODE_PTR;
	NewType.attr.isvolatile = FALSE;
	NewType.attr.isconst = FALSE;
	NewType.attr.isflat32 = ptr32;
	NewType.attr.unused = 0;

	// calculate new length
	usNTotal = LNGTHSZ + offsetof (lfPointer, pbase) + usVarOff;
	usNewLength = usNTotal - LNGTHSZ;

	// Determine where the new symbol goes in memory
	if (usNewLength <= usOldLen + 3 - LNGTHSZ) {
		pchDest = pchTypeStr;	// Copy new symbol over the old
	}
	else {
		pchDest = AllocNewStr (OldEntry, (ushort)(usNewLength + LNGTHSZ));
	}

	// Copy the symbol length
	*((ushort *)(pchDest))++ = usNewLength;

	// Copy fixed length portion of structure
	for (pchSrc = (uchar *)&NewType, i = offsetof (lfPointer, pbase); i; i--) {
		*pchDest++ = *pchSrc++;
	}

	// Copy variable length data including a name if there is one
	for (pchSrc = chVarData, i = usVarOff; i; i--) {
		*pchDest++ = *pchSrc++;
	}

	DASSERT(pchDest == OldEntry->TypeString + usNewLength + LNGTHSZ);
}






LOCAL void C6CnvtStructType (TENTRY *OldEntry)
{
	uchar	   *TypeString;
	int 		index;
	uchar	   *OldString;
	ushort		Count;				// number of fields
	ulong		Length; 			// length of structure
	int 		fList;				// new field spec list
	int 		i;
	CV_prop_t	property = {0}; 	// property byte
	plfStructure plf;
	uchar		chName[MAXSTRLEN + 1];
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	uchar		chVarData[MAXNUMERICLEN];
	uchar	   *pchVarData = chVarData;
	ushort		cbVarNew;			// Count of bytes of new variable length field
	uchar	   *pchSrc;
	uchar	   *pchDest;
	ushort		usOldLen;
	ulong		ulCount;

	OldEntry->flags.IsNewFormat = TRUE;
	TypeString = OldEntry->TypeString;
	usOldLen = *((ushort UNALIGNED *)(TypeString + 1));

	AddNewSymbols = TRUE; //???????
	OldString = TypeString;
	TypeString += 4;

	// get length in bits
	Length = C6GetLWordFromNumeric (&TypeString, NULL);

	// convert to bytes
	if (Length != 0) {
		Length = (Length - 1) / 8 + 1;
	}

	// Convert to new style Numeric
	cbVarNew = C7StoreLWordAsNumeric (chVarData, Length);

	ulCount = C6GetLWordFromNumeric(&TypeString, NULL);

	// If the count is above 64K (it should never be) then make it 64K

	Count = ulCount <= 0xFFFFL ? (ushort)ulCount : (ushort)0xFFFF;
	index = getindex (TypeString);		 // tList index
	fList = MergeLists ((ushort)index, (ushort)(getindex (TypeString)), Count);

	chName[0] = 0;
	if (TypeString < OldString + LENGTH (OldString) + 3) {
		if (*TypeString == OLF_NAME) {
			// name present
			TypeString++;
			memcpy (chName, TypeString, *TypeString + 1);
			TypeString += *TypeString + 1;
			if (TypeString < OldString + LENGTH (OldString) + 3) {
				property.packed = (char)(*TypeString == OLF_PACKED);
			}
			else {
				property.packed = FALSE;
			}
		}
		else {
			property.packed = (char)(*TypeString == OLF_PACKED);
		}
	}
	else {
		property.packed = FALSE;
	}

	// calculate new length
	usNTotal = LNGTHSZ + offsetof (lfStructure, data) + cbVarNew + chName[0] + 1;
	usNewLength = usNTotal - LNGTHSZ;


	// Determine where the new symbol goes in memory
	if (usNewLength <= usOldLen + 3 - LNGTHSZ) {
		pchDest = OldString;	// Copy new symbol over the old
	}
	else {
		pchDest = AllocNewStr (OldEntry, (ushort)(usNewLength + LNGTHSZ));
	}
	*((ushort *)pchDest)++ = usNewLength;
	plf = (plfStructure)pchDest;

	plf->leaf = LF_STRUCTURE;
	plf->count = Count;
	plf->field = fList;
	plf->property = property;
	plf->derived = 0;
	plf->vshape = 0;

	pchDest += offsetof (lfStructure, data);

	// Copy variable length "length" field
	for (pchSrc = chVarData, i = cbVarNew; i > 0; i--) {
		*pchDest++ = *pchSrc++;
	}

	// Copy the name field
	for (pchSrc = chName, i = chName[0] + 1; i; i--) {
		*pchDest++ = *pchSrc++;
	}

	DASSERT(pchDest == OldEntry->TypeString + usNewLength + LNGTHSZ);

}






LOCAL void C6CnvtBArrayType (TENTRY *OldEntry)
{
	lfBArray	NewType;
	uchar *		pchTypeStr;
	uchar *		pchTypeStrStart;
	uchar * 	pchSrc;
	uchar * 	pchDest;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	// UNDONE: usOldLen s/b something meaningful, 0 isn't.
	ushort		usOldLen = 0;		// Length of the old record excluding length and link.
	int 		i;


	OldEntry->flags.IsNewFormat = TRUE;

	// Walk through old record creating the new one on the stack

	pchTypeStrStart = pchTypeStr = OldEntry->TypeString; // get the string
	NewType.leaf = LF_BARRAY;
	pchTypeStr += 4;

	DASSERT(*pchTypeStr == OLF_INDEX);
	pchTypeStr++;
	NewType.utype = *((ushort *)(pchTypeStr))++;

	// calculate new length

	usNTotal = sizeof (lfBArray) + LNGTHSZ;
	usNewLength = usNTotal - LNGTHSZ;

	// Determine where the new symbol goes in memory

	if (usNewLength <= usOldLen + 3 - LNGTHSZ) {
		pchDest = pchTypeStrStart;	// Copy new symbol over the old
	}
	else {
		pchDest = AllocNewStr (OldEntry, (ushort)(usNewLength + LNGTHSZ));
	}

	// Copy the symbol length

	*((ushort *)(pchDest))++ = usNewLength;

	// Copy fixed length structure
	for (pchSrc = (uchar *)&NewType, i = sizeof (lfBArray); i; i--) {
		*pchDest++ = *pchSrc++;
	}
}






LOCAL void C6CnvtArrayType (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;
	uchar *		pchTypeStrStart;
	lfArray 	NewType;
	uchar		chVarData[MAXNUMERICLEN];
	uchar		chName[MAXSTRLEN + 1] = {0};
	uchar *		pchVarData = chVarData;
	uchar * 	pchSrc;
	uchar * 	pchDest;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	ushort		usOldLen;			// Length of the old record excluding length and link.
	ushort		cbVarNew;			// Count of bytes of new variable length field
	ushort		cbVarOld;			// Count of bytes of old variable length field
	ulong		ulLength;
	int 		i;


	OldEntry->flags.IsNewFormat = TRUE;

	// Walk through old record creating the new one on the stack
	pchTypeStrStart = pchTypeStr = OldEntry->TypeString; // get the string
	NewType.leaf = LF_ARRAY;
	pchTypeStr += 4;			// Advance to the length field

	// get length in bits
	ulLength = C6GetLWordFromNumeric (&pchTypeStr, &cbVarOld);

	// convert to bytes
	ulLength = ulLength >> 3;

	// Convert to new style Numeric
	cbVarNew = C7StoreLWordAsNumeric (pchVarData, ulLength);
	DASSERT(cbVarNew <= MAXNUMERICLEN);

	DASSERT(*pchTypeStr == OLF_INDEX);
	pchTypeStr++;
	NewType.elemtype = *((ushort *)(pchTypeStr))++;

	// Copy the index type if one was supplied
	usOldLen = *((ushort UNALIGNED *)(pchTypeStrStart + 1));
	if (usOldLen > (ushort)4 + cbVarOld) {
		DASSERT(*pchTypeStr == OLF_INDEX);
		pchTypeStr++;
		NewType.idxtype = *((ushort *)(pchTypeStr))++;
	}
	else{
		NewType.idxtype = 0x80 + 0x05;	// Old C7 T_USHORT value
	}

	// Copy the optional name or create a zero length one
	if (usOldLen > (ushort)(4 + cbVarOld + 3)) {
		// Old type does contain an optional name
		if (*pchTypeStr == OLF_NAME) {
			pchTypeStr++;
		}
		memcpy (chName, pchTypeStr, *pchTypeStr);
	}

	// calculate new length
	usNTotal = LNGTHSZ + offsetof (lfArray, data) + cbVarNew + chName[0] + 1;
	usNewLength = usNTotal - LNGTHSZ;

	// Determine where the new symbol goes in memory
	if (usNewLength <= usOldLen + 3 - LNGTHSZ) {
		pchDest = pchTypeStrStart;	// Copy new symbol over the old
	}
	else {
		pchDest = AllocNewStr (OldEntry, (ushort)(usNewLength + LNGTHSZ));
	}

	// Copy the symbol length

	*((ushort *)(pchDest))++ = usNewLength;

	// Copy fixed length structure
	for (pchSrc = (uchar *)&NewType, i = offsetof (lfArray, data); i; i--) {
		*pchDest++ = *pchSrc++;
	}

	// Copy variable length "length" field
	for (pchSrc = chVarData, i = cbVarNew; i; i--) {
		*pchDest++ = *pchSrc++;
	}

	// Copy the name field
	for (pchSrc = chName, i = chName[0] + 1; i; i--) {
		*pchDest++ = *pchSrc++;
	}
}



LOCAL void C6CnvtFString (TENTRY *OldEntry)
{
	lfArray 	NewType;
	uchar	   *pchTypeStr;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	ulong		ulLength;
	ushort		cbVarNew;			// Count of bytes of new variable length field
	ushort		cbVarOld;			// Count of bytes of old variable length field
	uchar		chVarData[MAXNUMERICLEN];
	uchar *		pchVarData = chVarData;
	uchar * 	pchSrc;
	uchar * 	pchDest;
	ushort		i;

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString;
	switch (*(pchTypeStr + 4)) {
		case 0:
			// fixed length string

			pchTypeStr += 5;
			ulLength = C6GetLWordFromNumeric (&pchTypeStr, &cbVarOld);
			cbVarNew = C7StoreLWordAsNumeric (pchVarData, ulLength);
			DASSERT(cbVarNew <= MAXNUMERICLEN);
			NewType.leaf = LF_ARRAY;
			NewType.elemtype = T_CHAR;
			NewType.idxtype = T_USHORT;

			// calculate new length
			usNTotal = LNGTHSZ + offsetof (lfArray, data) + cbVarNew + 1;
			usNewLength = usNTotal - LNGTHSZ;

			pchDest = AllocNewStr (OldEntry, usNTotal);

			// Copy the symbol length, fixed data, array length and null name

			*((ushort *)(pchDest))++ = usNewLength;
			for (pchSrc = (uchar *)&NewType, i = offsetof (lfArray, data); i; i--) {
				*pchDest++ = *pchSrc++;
			}
			for (pchSrc = chVarData, i = cbVarNew; i; i--) {
				*pchDest++ = *pchSrc++;
			}
			*pchDest++ = 0;
			break;

		case 1:
			// variable length string
			*((ushort *)pchTypeStr)++ = 2;
			*((ushort *)pchTypeStr)++ = LF_NOTTRAN;
			break;

		default:
			// unrecognized tag
			DASSERT(FALSE);
			break;
	}


}



LOCAL void C6CnvtProcType (TENTRY *OldEntry)
{
	uchar	   *pchDest;
	uchar	   *pchTypeStr;
	lfProc		NewType;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	ulong		ulCount;

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString; // get the string

	// calculate new length

	usNTotal = LNGTHSZ + sizeof (lfProc);
	usNewLength = usNTotal - LNGTHSZ;

	// Set constant fields

	NewType.leaf = LF_PROCEDURE;
	pchTypeStr += 5;
	if (*pchTypeStr == OLF_INDEX) {
		pchTypeStr++;
		NewType.rvtype = *((ushort *)(pchTypeStr))++;
	}
	else {
		NewType.rvtype = *pchTypeStr;
		pchTypeStr++;
	}
	switch (*pchTypeStr++) {			// get old call type
		case 0x63 :
			NewType.calltype = CV_CALL_NEAR_C;
			break;

		case 0x64 :
			NewType.calltype = CV_CALL_FAR_C;
			break;

		case 0x73 :
			NewType.calltype = CV_CALL_FAR_PASCAL;
			break;

		case 0x74 :
			NewType.calltype = CV_CALL_NEAR_PASCAL;
			break;

		case 0x95 :
			NewType.calltype = CV_CALL_NEAR_FAST;
			break;

		case 0x96 :
			NewType.calltype = CV_CALL_FAR_FAST;
			break;

		case 0x97 :
			NewType.calltype = CV_CALL_SKIPPED;
			break;

		default:
			DASSERT(FALSE);
			break;
	}
	NewType.reserved = 0;

	ulCount = C6GetLWordFromNumeric (&pchTypeStr, NULL);

	NewType.parmcount = (ulCount <= 0xFFFFL) ? (ushort)ulCount : (ushort)0xFFFF;
	DASSERT(*pchTypeStr == OLF_INDEX);
	pchTypeStr++;

	if (NewType.parmcount) {
		NewType.arglist = *((ushort *)pchTypeStr);
		// Go ahead and convert the arglist type also
		C6CnvtArgList(NewType.arglist, NewType.parmcount);
	}
	else {
		NewType.arglist = ZEROARGTYPE;	  // Reference our own internal predefined type
	}

	if (usNewLength <= *((ushort UNALIGNED *)(pchTypeStr + 1)) + 3 - LNGTHSZ) {
		pchDest = OldEntry->TypeString;
	}
	else {
		pchDest = AllocNewStr (OldEntry, (ushort)(usNewLength + LNGTHSZ));
	}
	*((ushort *)(pchDest))++ = usNewLength;
	*((lfProc *)(pchDest))++ = NewType;

	DASSERT(pchDest == OldEntry->TypeString + usNewLength + LNGTHSZ);
}





/**
 *
 *	MergeLists
 *
 *	Given the indices to a type index list, a name offset list, and
 *	a count, this routine converts them into a field specification
 *	list with member fields and returns an index to the new list.
 *
 */

LOCAL ushort MergeLists (ushort tList, ushort nList, ushort Count)
{
	uchar  *TypeIndexString, *NameOffsetString;
	uchar  *ScratchString;			 // temporary work
	uchar  *ScratchSave;
	uchar  *OffsetStart;
	ushort	Length;
	ushort	FinalLength;
	int 	i;
	CV_fldattr_t mattrib = {0};
	TENTRY *TypeEntry, *NameEntry;
	CV_typ_t	forward;

	mattrib.access = CV_public;		// public access field

	TypeEntry = GetTypeEntry ((CV_typ_t)(tList - 512), &forward);
	NameEntry = GetTypeEntry ((CV_typ_t)(nList - 512), &forward);

	// Get the two strings to walk
	TypeIndexString = TypeEntry->TypeString;
	NameOffsetString = NameEntry->TypeString;

	// Calculate the longest possible result
	// We are intentionally wasting memory to avoid walking the list
	// two times.
	Length = LNGTHSZ							// Size of length field
			 + MAXPAD							// So we can align the start
			 + offsetof (lfFieldList, data)		// Field leaf size
			 + (LENGTH (NameOffsetString) - 1)	// Variable length data size
			 + (Count							// Number of fields times
			 * (offsetof (lfMember, offset)		// Size LF_MEMBER structure plus
				+ MAXPAD						// Maximum number of pad bytes per field
				+ MAXC6NUMERICGROWTH)); 		   // Maximum possible growth of numeric field

	TypeIndexString += 4;			// skip to indices
	NameOffsetString += 4;			// skip to names

	ScratchString = GetScratchString (Length); // get a scratch string

	//M00SPEED This logic could be moved to GetScratchSize
	// This garantees we can do padding when running with any malloc version
	while((ulong)ScratchString & MAXPAD) {	// Make sure buffer starts on a four byte boundry
		ScratchString++;
	}

	ScratchSave = ScratchString;

	// Start building new C7 field list
	ScratchString += LNGTHSZ;	// Skip Length (fill in later with exact size)

	*((ushort *)ScratchString)++ = LF_FIELDLIST;
	for (; Count > 0; Count --) {
		DASSERT(*NameOffsetString == OLF_NAME);
		DASSERT(*TypeIndexString == OLF_INDEX);
		NameOffsetString ++;		// skip OLF_NAME
		*((ushort *)ScratchString)++ = LF_MEMBER;
		*((ushort *)ScratchString)++ = getindex (TypeIndexString);
		*((CV_fldattr_t *)ScratchString)++ = mattrib;

		// Temporarily skip over the string

		OffsetStart = NameOffsetString + *NameOffsetString + 1;
		ConvertNumeric (&OffsetStart, &ScratchString);

		// copy over the name
		for (i = *NameOffsetString + 1; i; i --) {
			*ScratchString ++ = *NameOffsetString ++;
		}
		// update the name offset string
		NameOffsetString = OffsetStart;

		// Pad the new leaf
		if ((ulong)ScratchString & MAXPAD) {
			*ScratchString = (uchar)(0xF0 + MAXPAD + 1 - ((ulong)ScratchString & MAXPAD));
			while((ulong)(++ScratchString) & MAXPAD) {
				*ScratchString = 0;
			}
		}
	}
	TypeIndexString = TypeEntry->TypeString;
	NameOffsetString = NameEntry->TypeString;

	FinalLength = ScratchString - ScratchSave;
	DASSERT(FinalLength <= Length);
	*((ushort *)(ScratchSave)) = FinalLength - LNGTHSZ;

	// Allocate memory and copy the type string into it

	TypeIndexString = AllocNewStr (TypeEntry, FinalLength);
	TypeEntry->flags.IsNewFormat = TRUE;
	memcpy (TypeIndexString, ScratchSave, FinalLength);
	return (tList);
}






LOCAL void C6CnvtArgList (ushort usArgList, ushort usCount)
{
	uchar *		pchTypeStr;
	uchar * 	pchTypeStrBase; 	// The base of the original type string
	plfArgList	plf;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	ushort		usfInTmp;			// True if string stored in temporary buffer
	uchar * 	pchDest;
	ushort		i;
	uchar * 	pchDestBase;
	TENTRY *OldEntry;
	CV_typ_t	forward;

	OldEntry = GetTypeEntry ((CV_typ_t)(usArgList - 512), &forward);
	if (OldEntry->flags.IsNewFormat) {
	    return;
	}

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString; // get the string
	pchTypeStrBase = pchTypeStr;
	DASSERT((pchTypeStr[3] == OLF_LIST) || (pchTypeStr[3] == OLF_ARGLIST) ||
	  ((usCount != 0) && (pchTypeStr[3] == OLF_NIL)));

	// calculate new length

	usNTotal = LNGTHSZ + offsetof (lfArgList, arg) + (sizeof(CV_typ_t) * usCount);
	usNewLength = usNTotal - LNGTHSZ;

	// Get some memory to put the result in

	if (usNewLength + LNGTHSZ <= LENGTH (pchTypeStr) + 3) {
		// Get some scratch memory so we don't wipe out the memory we are
		// are attempting to rewrite.

		usfInTmp = TRUE;
		pchDest = GetScratchString (usNewLength + LNGTHSZ);
	}
	else {
		usfInTmp = FALSE;
		pchDest = Alloc (usNewLength + LNGTHSZ);
	}
	pchDestBase = pchDest;

	pchTypeStr += 4;		// Skip to the arguments;
	*((ushort*)pchDest)++ = usNewLength;
	plf = (plfArgList) pchDest;
	plf->leaf = LF_ARGLIST;
	plf->count = usCount;

	// Loop through copying the indexes from the old to the new.

	for (i = 0; i < usCount; i++) {
		plf->arg[i] = getindex (pchTypeStr);
	}
	pchDest = (uchar *) &(plf->arg[i]);

	if (usfInTmp) {
		// Copy the new string over the old one
		memcpy (OldEntry->TypeString, pchDestBase, usNewLength + LNGTHSZ);
		DASSERT(pchDest == pchDestBase + usNewLength + LNGTHSZ);
	}
	else {
		FreeAllocStrings (OldEntry);
		OldEntry->flags.IsMalloced = TRUE;
		OldEntry->TypeString = pchDestBase;
		DASSERT(pchDest == OldEntry->TypeString + usNewLength + LNGTHSZ);
	}
}


LOCAL void C6CnvtNilType (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;

	DASSERT(!OldEntry->flags.IsNewFormat);

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString; // get the string

	*((ushort *)pchTypeStr)++ = 2;		 // Length of leaf
	*((ushort *)pchTypeStr)++ = LF_NULL; // The leaf
}



LOCAL void C6CnvtNotTranType (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;

	DASSERT(!OldEntry->flags.IsNewFormat);

//M00BUG - Should add a warning that a type wasn't translated.

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString; // get the string

	*((ushort *)pchTypeStr)++ = 2;		 // Length of leaf
	*((ushort *)pchTypeStr)++ = LF_NOTTRAN; // The leaf
}



LOCAL void C6CnvtLabelType (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;
	plfLabel	pNewType;
	uchar * 	pchDest;
	uchar * 	pchDestBase;		// The start of the new string
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.

	DASSERT(!OldEntry->flags.IsNewFormat);

	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString; // get the string

	// calculate new length
	// M00SPEED These are all constants
	usNTotal = LNGTHSZ + sizeof(lfLabel);
	usNewLength = usNTotal - LNGTHSZ;


	// Get memory for new type
	pchDest = Alloc (usNewLength + LNGTHSZ);
	pchDestBase = pchDest;
	pNewType = (plfLabel)(pchDest + LNGTHSZ);

	// Insert the new length and new type
	*((ushort *)pchDest) = usNewLength;
	pNewType->leaf = LF_LABEL;

	// 0x73 == old LF_FAR, 0x74 == old LF_NEAR
	//Make sure the code label is one of the two types
	DASSERT(*(pchTypeStr + 5) == 0x73 || *(pchTypeStr + 5) == 0x74);

	// Get the new type
	if (*(pchTypeStr + 5) == 0x73) {
		pNewType->mode = CV_LABEL_FAR;
	}
	else {
		pNewType->mode = CV_LABEL_NEAR;
	}

	pchDest += LNGTHSZ + sizeof (lfLabel);

	// Change entry to point to the new string

	FreeAllocStrings (OldEntry);
	OldEntry->flags.IsMalloced = TRUE;
	OldEntry->TypeString = pchDestBase;

	DASSERT(pchDest == OldEntry->TypeString + *((ushort *)(OldEntry->TypeString)) + LNGTHSZ);
}



LOCAL void C6CnvtBitfieldType (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;
	uchar *		pchTypeStrStart;
	plfBitfield	pNewType;
	uchar * 	pchDest;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.

	OldEntry->flags.IsNewFormat = TRUE;

	// calculate new length
	// M00SPEED These are all constants
	usNTotal = LNGTHSZ + sizeof(lfBitfield);
	usNewLength = usNTotal - LNGTHSZ;

	pchTypeStrStart = pchTypeStr = OldEntry->TypeString; // get the string
	pchTypeStr += 4;			// Advance to the length field

	// Get memory for new type
	pchDest = Alloc (usNewLength + LNGTHSZ);
	pNewType = (plfBitfield)(pchDest + LNGTHSZ);

	// Insert the new length and new type
	*((ushort *)pchDest) = usNewLength;
	pNewType->leaf = LF_BITFIELD;

	// Copy the length in bits of the object
	pNewType->length = *pchTypeStr++;

	// Copy the base type
	// Note that 0x7c was UNSINT and 0x7d was SGNINT, in CV3 days.

	DASSERT(*pchTypeStr == 0x7c || *pchTypeStr == 0x7d);
	DASSERT(pNewType->length <= 32);
	if (pNewType->length <= 16) {
		 pNewType->type = (*pchTypeStr++ == 0x7d) ? T_SHORT : T_USHORT;
	}
	else {
		 pNewType->type = (*pchTypeStr++ == 0x7d) ? T_LONG : T_ULONG;
	}

	// Copy bit position in the byte, word, ect.
	pNewType->position = *pchTypeStr++;

	// Change entry to point to the new string

	FreeAllocStrings (OldEntry);
	OldEntry->flags.IsMalloced = TRUE;
	OldEntry->TypeString = pchDest;

	pchDest += LNGTHSZ + sizeof (lfBitfield);

	DASSERT(pchDest == OldEntry->TypeString + *((ushort *)(OldEntry->TypeString)) + LNGTHSZ);
}



/** 	AllocNewStr - allocate new type string buffer
 *
 *		Entry	OldEntry = pointer to type entry structure
 *				length = length of new type string
 *
 *		Exit	OldEntry->TypeString freed and new buffer allocated
 *
 *		Returns pointer to new string
 */


LOCAL uchar *AllocNewStr (TENTRY *OldEntry, ushort length)
{
	uchar	   *pNew;

	if ((length + LNGTHSZ) > POOL2SIZE) {
		pNew = Alloc (length + LNGTHSZ);
	}
	else if ((length + LNGTHSZ) > POOLSIZE) {
		pNew = Pool2Alloc ();
	}
	else {
		pNew = PoolAlloc ();
	}
	FreeAllocStrings (OldEntry);
	if ((length + LNGTHSZ) > POOL2SIZE) {
		OldEntry->flags.IsMalloced = TRUE;
	}
	else if ((length + LNGTHSZ) > POOLSIZE) {
		OldEntry->flags.IsPool2 = TRUE;
	}
	else {
		OldEntry->flags.IsPool = TRUE;
	}
	OldEntry->TypeString = pNew;
	return (pNew);
}


LOCAL void C6CnvtCobTypeRef (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;
	uchar * 	pchDest;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	plfCobol0	pNewType;

	DASSERT(!OldEntry->flags.IsNewFormat);
	IsMFCobol = TRUE;
	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString;

	// calculate new length.  Since all we are doing is copying the old
	// data, we just increase the length by to allow for large record type

	usNTotal = LNGTHSZ + *((ushort UNALIGNED *)(pchTypeStr + 1)) + 1;
	usNewLength = usNTotal - LNGTHSZ;

	// Get memory for new type

	pchDest = Alloc (usNTotal);
	pNewType = (plfCobol0)(pchDest + LNGTHSZ);

	// Insert the new length and new type and copy the remainder of
	// of the type string over

	*((ushort *)pchDest) = usNewLength;
	pNewType->leaf = LF_COBOL0;
	memmove (&pNewType->type, pchTypeStr + 4, *((ushort UNALIGNED *)(pchTypeStr + 1)) - 1);

	// Change entry to point to the new string

	FreeAllocStrings (OldEntry);
	OldEntry->flags.IsMalloced = TRUE;
	OldEntry->TypeString = pchDest;
}



LOCAL void C6CnvtCobol (TENTRY *OldEntry)
{
	uchar *		pchTypeStr;
	uchar * 	pchDest;
	ushort		usNTotal;			// New length of symbol including length field
	ushort		usNewLength;		// New paded length excluding length field.
	plfCobol1	pNewType;

	DASSERT(!OldEntry->flags.IsNewFormat);
	IsMFCobol = TRUE;
	OldEntry->flags.IsNewFormat = TRUE;
	pchTypeStr = OldEntry->TypeString;

	// calculate new length.  Since all we are doing is copying the old
	// data, we just increase the length by to allow for large record type

	usNTotal = LNGTHSZ + *((ushort UNALIGNED *)(pchTypeStr + 1)) + 1;
	usNewLength = usNTotal - LNGTHSZ;

	// Get memory for new type

	pchDest = Alloc (usNTotal);
	pNewType = (plfCobol1)(pchDest + LNGTHSZ);

	// Insert the new length and new type and copy the remainder of
	// of the type string over

	*((ushort *)pchDest) = usNewLength;
	pNewType->leaf = LF_COBOL1;
	memmove (&pNewType->data, pchTypeStr + 4, *((ushort UNALIGNED *)(pchTypeStr + 1)) - 1);

	// Change entry to point to the new string

	FreeAllocStrings (OldEntry);
	OldEntry->flags.IsMalloced = TRUE;
	OldEntry->TypeString = pchDest;
}