toolsandutils/e32tools/elf2e32/source/deffile.cpp
author Mike Kinghan <mikek@symbian.org>
Tue, 16 Nov 2010 14:32:12 +0000
branchGCC_SURGE
changeset 79 f7dee603db09
parent 0 83f4b4db085c
child 10 d4b442d23379
permissions -rw-r--r--
[GCCE] We need a way for the HAL config extension to parameterise the HAL config file (.hcf) that will be used, depending upon the toolchain we are building with. E.g. if we are building BeagleBoard with RVCT we can configure hardware floating point because we have ARM's vfp math libraries; if we are building it with GCC, we lack this library support.

// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Implementation of the Class DefFile for the elf2e32 tool
// @internalComponent
// @released
// 
//

//
#include <stdio.h>
#include <iostream>
#include <stdlib.h>

#include "pl_symbol.h"
#include "deffile.h"
#include "errorhandler.h"

#ifdef __LINUX__
    #include "h_utl.h"
    #define STRUPR strupr
#else 
    #define STRUPR _strupr
#endif

using std::cerr;
using std::cout;
using std::endl;

#define SUCCESS 1
#define FAILURE 0

/**
Destructor to release all the allocated memory
@internalComponent
@released
*/
DefFile::~DefFile()
{
	if(iSymbolList && iSymbolList->size())
	{
		SymbolList::iterator aItr = iSymbolList->begin();
		SymbolList::iterator last = iSymbolList->end();
		Symbol *temp;

		while(aItr != last)
		{
			temp = *aItr;
			aItr++;
			delete temp;
		}
		iSymbolList->clear();
	}
	delete iSymbolList;
}
/**
Function to Get File Size.
@param fptrDef - File pointer to DEF file
@internalComponent
@released
*/
int DefFile::GetFileSize(FILE *fptrDef)
{
	int fileSize,status;

	status=fseek(fptrDef, 0, SEEK_END);
	if(status!=0)
	{
		throw FileError(FILEREADERROR,iFileName);
	}
	fileSize=ftell(fptrDef);
	rewind(fptrDef);

	return fileSize;

}

/**
Function to Open File and read it in memory.
@param defFile - DEF File name
@internalComponent
@released
*/
char* DefFile::OpenDefFile(char * defFile)
{
	int fileSize;
	char *defFileEntries;
	FILE *fptrDef;

	iFileName=defFile;
	if((fptrDef=fopen(defFile,"rb"))==NULL)
	{
		throw FileError(FILEOPENERROR,defFile);
	}

	fileSize=GetFileSize(fptrDef);

	if((defFileEntries= new char[fileSize+2]) ==NULL)
	{
		throw MemoryAllocationError(MEMORYALLOCATIONERROR,defFile);
	}

	//Getting whole file in memory
	if(!fread(defFileEntries, fileSize, 1, fptrDef))
	{
		throw FileError(FILEREADERROR,defFile);
	}

	//Adding ENTER at end
	*(defFileEntries+fileSize)='\n';
	//Adding '\0' at end
	*(defFileEntries+fileSize+1)='\0';

	fclose(fptrDef);

	return defFileEntries;

}

/**
Function to Parse Def File which has been read in buffer.
@param defFileEntries - pointer to def file entries which has been read in buffer
@internalComponent
@released
*/
void DefFile::ParseDefFile(char *defFileEntries)
{
	iSymbolList = new SymbolList;

	int ordinalNo = 0;
	int symbolType=SymbolTypeCode;
	int PreviousOrdinal=0;
	char MultiLineStatement[1024]="";
	bool NAMEorLIBRARYallowed=true;
	int LineNum = 0;
	bool isComment;

	char *lineToken;
	int aLineLength = 0, width = 0;
	unsigned i;
	char *ptrEntry,*ptrEntryType;
	char entryType[256];
	bool entryFlag;


	lineToken=strtok(defFileEntries,"\n");
	while(lineToken != NULL)
	{
		symbolType=SymbolTypeCode;
		isComment=false;
		entryType[0]='\0';
		aLineLength = strlen(lineToken);
		LineNum++;

		if (lineToken == NULL || lineToken[0]==13)
		{
			lineToken=strtok(NULL,"\n");
			continue;
		}

		// comment lines
		if (lineToken[0] == ';')
		{
			lineToken=strtok(NULL,"\n");
			continue;
		}

		ptrEntry=lineToken;

		if((!strstr(lineToken, "NONAME") && ((ptrEntryType=strstr(lineToken, "NAME")) != NULL)) ||
			((ptrEntryType=strstr(lineToken, "EXPORTS")) != NULL) ||
			((ptrEntryType=strstr(lineToken, "IMPORTS")) != NULL) ||
			((ptrEntryType=strstr(lineToken, "SECTIONS")) != NULL) ||
			((ptrEntryType=strstr(lineToken, "LIBRARY")) != NULL) ||
			((ptrEntryType=strstr(lineToken, "DESCRIPTION")) != NULL)||
			((ptrEntryType=strstr(lineToken, "STACKSIZE")) != NULL)||
			((ptrEntryType=strstr(lineToken, "VERSION")) != NULL)
			)
		{
			entryFlag=true;

			for(i=0; ptrEntry!=ptrEntryType; i++,ptrEntry++)
			{
				switch(lineToken[i])
				{
				case ' ':
				case '\t':
					continue;
				default:
					entryFlag=false;
					break;
				}
				if(entryFlag==false)
					break;
			}

			if(entryFlag==false && !strcmp(MultiLineStatement,""))
			{
				throw DEFFileError(UNRECOGNIZEDTOKEN,iFileName,LineNum,lineToken);
			}

			if(entryFlag==true)
			{
				switch(ptrEntryType[0])
				{
				case 'E':
				case 'I':
				case 'L':
				case 'V':
					width=7;
					break;
				case 'S':
					if(ptrEntryType[1]=='E')
						width=8;
					else
						width=9;
					break;
				case 'N':
					width=4;
					break;
				case 'D':
					width=11;
					break;
				}
			}

			if(entryFlag==true)
			{
  				for(i=i+width; i<strlen(lineToken); i++)
				{
					switch(lineToken[i])
					{
					case ' ':
					case '\t':
						continue;
					case '\r':
					case '\0':
						break;
					default:
						entryFlag=false;
						break;
					}

					if(entryFlag==false)
						break;
				}
			}

			if(entryFlag==false && !strcmp(MultiLineStatement,""))
			{
				throw DEFFileError(UNRECOGNIZEDTOKEN,iFileName,LineNum,lineToken+i);
			}

			if(entryFlag==true)
			{
				strncpy(entryType, ptrEntryType, width);
				entryType[width]='\0';

				switch(ptrEntryType[0])
				{
				case 'E':		// check for multi-line sections starting
					strcpy(MultiLineStatement, STRUPR(entryType)); // Uppercase token
					NAMEorLIBRARYallowed = false;
					lineToken = strtok(NULL, "\n" ); // Get the next line
					continue;
				case 'N':
					break;
				case 'L':
					break;
				case 'D':
					break;
				case 'S':
				case 'V':
					if(entryType[1]!='E')
					{
						// set MULTI-LINE statement to OFF
						strcpy(MultiLineStatement, STRUPR(entryType)); // Uppercase token
						// check single-line statements are specified correctly
						// check NAME or LIBRARY statements aren't supplied incorrectly
						if (!strcmp(entryType, "NAME") ||
							!strcmp(entryType, "LIBRARY")
							)
						{
							if (NAMEorLIBRARYallowed == false)
							{
								throw DEFFileError(NAMELIBRARYNOTCORRECT,iFileName,LineNum,lineToken);
							}
							lineToken=strtok(NULL,"\n");
							continue;
						}
						NAMEorLIBRARYallowed = false;
						lineToken=strtok(NULL,"\n");
						continue;
					}
					continue;
				case 'I':
					strcpy(MultiLineStatement, STRUPR(entryType)); // Uppercase token
					lineToken = strtok(NULL, "\n" ); // Get the next line
					continue;
				}
			}

		}
		else
		{
			if (!strcmp(MultiLineStatement,""))
		    {
				throw DEFFileError(EXPORTSEXPECTED,iFileName,LineNum,lineToken);
			}
		}	
			
		// Get Export entries
		if (!strcmp(MultiLineStatement,"EXPORTS"))
		{
			Symbol aSymbol(NULL, SymbolTypeCode);
			if( Tokenize(lineToken, LineNum, aSymbol) )
			{
				Symbol *newSymbolEntry = new Symbol(aSymbol);
				iSymbolList->push_back(newSymbolEntry);

				ordinalNo = aSymbol.OrdNum();
				//Check for ordinal sequence
				if (ordinalNo != PreviousOrdinal+1)
		   		{
					throw DEFFileError(ORDINALSEQUENCEERROR,iFileName,LineNum,(char*)aSymbol.SymbolName());
				}

				PreviousOrdinal = ordinalNo;

			}
			lineToken=strtok(NULL,"\n");
			continue;
		}
		else if(strcmp(MultiLineStatement,"")!=0)//For entry other than exports
			lineToken = strtok(NULL, "\n" ); // Get the next line

	}//End of while
}

/**
This Function calls LineToken's Tokenize function.
@param aTokens   - Input string at the current line number
@param aLineNum  - Current line number
@param aSymbol   - Symbol to be populated while parsing the line.
Return value     - It returns true if a valid def file entry is found.
@internalComponent
@released
*/
bool DefFile::Tokenize(char* aTokens, int aLineNum, Symbol& aSymbol)
{
	/*
	 * Pattern to match is:
	 * START\s*(\S+)\s+@\s*(d+)\s*(NONAME)?\s*(R3UNUSED)?\s*(ABSENT)?\s*(;\s*(.*))END
	 */
	LineToken aLine(iFileName, aLineNum, aTokens, &aSymbol);
	return aLine.Tokenize();
}


char * DefFilePatterns[] =
	{
		"NONAME",//index 0
		"DATA",
		"R3UNUSED",
		"ABSENT"
	};

#define DEF_NONAME		0
#define DEF_DATA		1
#define DEF_R3UNUSED	2
#define DEF_ABSENT		3

/**
This constructor creates an instance of LineToken class.
@param aFileName - Def File Name.
@param aLineNum  - Current line number
@param aLn       - Input string at the current line number
@param aSym      - Symbol to be populated while parsing the line.
@internalComponent
@released
*/
LineToken::LineToken(char* aFileName, int aLineNum, char *aLn, Symbol* aSym) : \
		iLine(aLn) , iSymbol(aSym) , iOffset(0), iState(EInitState),iFileName(aFileName), iLineNum(aLineNum) 
{
}

/**
This function tokenizes the line and populates a symbol entry 
if there is one.
Return Value - True, if the current line has a valid def entry.
@internalComponent
@released
*/
bool LineToken::Tokenize()
{
	while (1) 
	{
		switch( iState )
		{
		case EFinalState:
			return true;
		case EInitState:
			if( *(iLine + iOffset) == '\0' || 
				*(iLine + iOffset) == '\r' || 
				*(iLine + iOffset) == '\n')
			{
				/*
				 * Skip empty lines.
				 */
				return false;
			}
			else
			{
				NextToken();
			}
			break;
		default:
			NextToken();
			break;
		}
	}
	return false;
}

/**
This function parses a line of the def file based on the current 
state it is in.
@internalComponent
@released
*/
void LineToken::NextToken()
{
	int aCurrentPos = 0;
	char *aSymbolName;

	switch( iState )
	{
	case EInitState:
		if(IsWhiteSpace((iLine + iOffset), aCurrentPos))
		{
			IncrOffset(aCurrentPos);
		}

		if(IsWord(iLine + iOffset, aCurrentPos))
		{
			SetState(ESymbolName);
		}
	break;

	case ESymbolName:
	{
		// Get the length of the symbol
		IsWord(iLine + iOffset, aCurrentPos);

		char *cmt = strchr(iLine + iOffset, ';');
		char *aAlias = strchr(iLine + iOffset, '=');

		if( aAlias && (!cmt || (aAlias < cmt)) )
		{
			int aAliasPos = aAlias - (iLine+ iOffset);

			//Check if alias name is also supplied, they should be separated 
			// by whitespace, i.e., SymbolName=AliasName is valid while, 
			// SymbolName =AliasName is invalid.
			if( aAliasPos > aCurrentPos)
			{
				char *aToken = (iLine + iOffset + aCurrentPos);
				throw DEFFileError(UNRECOGNIZEDTOKEN, iFileName, iLineNum, aToken);
			}

			aSymbolName = new char[aAliasPos+1];
			strncpy(aSymbolName, iLine + iOffset, aAliasPos);
			aSymbolName[aAliasPos] = '\0';
			char *aExportName = new char[aCurrentPos - aAliasPos + 1];
			strncpy(aExportName, aAlias +1, (aCurrentPos - aAliasPos));
			aExportName[(aCurrentPos - aAliasPos)] = '\0';
			iSymbol->ExportName(aExportName);
		}
		else
		{
			aSymbolName = new char[aCurrentPos+1];
			strncpy(aSymbolName, iLine+ iOffset, aCurrentPos);
			aSymbolName[aCurrentPos] = '\0';
		}
		iSymbol->SymbolName(aSymbolName);
		
		IncrOffset(aCurrentPos);

		if(IsWhiteSpace((iLine + iOffset), aCurrentPos))
		{
			IncrOffset(aCurrentPos);
		}
		
		if(*(iLine+iOffset) == '@')
		{
			SetState(EAtSymbol);
			IncrOffset(1);
		}
		else
		{
			/*
			 * The first non-whitespace entry in a line is assumed to be the 
			 * symbol name and a symbol name might also have a '@' char. Hence
			 * there MUST be a whitespace between symbol name and '@'.
			 */
			throw DEFFileError(ATRATEMISSING,iFileName,iLineNum,(iLine+iOffset));
		}
	}
	break;

	case EAtSymbol:
		if(IsWhiteSpace((iLine + iOffset), aCurrentPos))
		{
			IncrOffset(aCurrentPos);
		}
		
		SetState(EOrdinal);
		break;
	case EOrdinal:
	{
		if(!IsDigit(iLine+iOffset, aCurrentPos ) )
		{
			throw DEFFileError(ORDINALNOTANUMBER, iFileName, iLineNum, (iLine+iOffset));
		}
		char aTmp[32];
		strncpy(aTmp, iLine+iOffset, aCurrentPos);
		aTmp[aCurrentPos] = '\0';
		int aOrdinal = atoi(aTmp);
		iSymbol->SetOrdinal(aOrdinal);

		IncrOffset(aCurrentPos);

		if(IsWhiteSpace((iLine + iOffset), aCurrentPos))
		{
			IncrOffset(aCurrentPos);
		}
		SetState(EOptionals);
	}
	break;

	case EOptionals:
		{
		int aPrevPatternIndex, aPatternIdx = 0;
		aPrevPatternIndex = -1;
		while (*(iLine + iOffset) != '\n' || *(iLine + iOffset) != '\r')
		{
			if(IsPattern(iLine+iOffset, aCurrentPos, aPatternIdx) )
			{
				switch(aPatternIdx)
				{
				case DEF_NONAME:
					break;
				case DEF_DATA:
					iSymbol->CodeDataType(SymbolTypeData);

					IncrOffset(aCurrentPos);
					if(IsWhiteSpace((iLine + iOffset), aCurrentPos))
					{
						IncrOffset(aCurrentPos);
					}
					if(IsDigit(iLine+iOffset, aCurrentPos ) )
					{
						char aSymSz[16];
						strncpy(aSymSz, (iLine + iOffset), aCurrentPos);
						aSymSz[aCurrentPos] = '\0';
						iSymbol->SetSymbolSize(atoi(aSymSz));
					}
					break;
				case DEF_R3UNUSED:
					iSymbol->R3Unused(true);
					break;
				case DEF_ABSENT:
					iSymbol->SetAbsent(true);
					break;
				default:
					break;
				}

				/*
				 * NONAME , DATA, R3UNUSED and ABSENT, all the 3 are optional. But, if more than
				 * one of them appear, they MUST appear in that order. 
				 * Else, it is not accepted.
				 */
				if( aPrevPatternIndex >= aPatternIdx)
				{
					throw DEFFileError(UNRECOGNIZEDTOKEN, iFileName, iLineNum,(iLine + iOffset));
				}
				aPrevPatternIndex = aPatternIdx;

				IncrOffset(aCurrentPos);
				
				if(IsWhiteSpace((iLine + iOffset), aCurrentPos))
				{
					IncrOffset(aCurrentPos);
				}
			}
			else
			{
				if( *(iLine + iOffset) == ';' )
				{
					SetState(EComment);
					IncrOffset(1);
					return;
				}
				else if( *(iLine + iOffset) == '\0' || 
						 *(iLine + iOffset) == '\r' || 
						 *(iLine + iOffset) == '\n')
				{
					SetState(EFinalState);
					return;
				}
				else
				{
					throw DEFFileError(UNRECOGNIZEDTOKEN, iFileName, iLineNum,(iLine + iOffset));
				}
			}
		}
		}
	break;

	case EComment:
	{
		if(IsWhiteSpace(iLine + iOffset, aCurrentPos))
		{
			IncrOffset(aCurrentPos);
		}
		
	
		int aLen = strlen(iLine + iOffset);
		if( *(iLine + iOffset + aLen - 1 ) == '\n' ||  *(iLine + iOffset + aLen - 1 ) == '\r')
			aLen -=1;

		char * aComment = new char[ aLen + 1];
		strncpy( aComment, iLine + iOffset, aLen);
		aComment[aLen] = '\0';

		IncrOffset(aLen);

		iSymbol->Comment(aComment);
		SetState(EFinalState);
	}
	break;

	case EFinalState:
		return;
	default:
		break;	
	}
}

/**
This function returns true if the string starts with one
of the fixed patterns.
It also updates the length  and index of this pattern.
@param aChar - Line Token
@param aTill - Length of the pattern
@param aTill - Index of the pattern
Return Value - True, if the string starts with one of the patterns.
@internalComponent
@released
*/
bool LineToken::IsPattern(char* aStr, int& aTill, int& aIndex)
{
	int pos = 0;
	int aLength;
	int size = sizeof(DefFilePatterns)/sizeof(char*);
	while(size > pos)
	{
		aLength = strlen(DefFilePatterns[pos]);
		if(!strncmp(aStr, DefFilePatterns[pos], aLength))
		{
			aTill = aLength;
			aIndex = pos;
			return true;
		}
		pos++;
	}
	return false;
}

/**
This function returns true if the string starts with digits.
It also updates the length of this digit string.
@param aChar - Line Token
@param aTill - Length of the digit string
Return Value - True, if the string starts with digit(s)
@internalComponent
@released
*/
bool LineToken::IsDigit(char *aChar, int &aTill)
{
	int pos = 0;
	if( aChar[pos] - '0' >= 0 &&  aChar[pos] - '0' <= 9)
	{
		pos++;
		while(aChar[pos] - '0' >= 0 &&  aChar[pos] - '0' <= 9)
		{
			pos++;
		}
		aTill = pos;
		return true;
	}
	else
	{
		return false;
	}
}

/**
This function returns true if the string starts with white space.
It also updates the length of this white string!
@param aStr - Line Token
@param aTill - Length of the white string
Return Value - True, if the string starts with whitespace
@internalComponent
@released
*/
bool LineToken::IsWhiteSpace(char *aStr, int &aTill)
{
	int pos = 0;
	switch( aStr[pos] )
	{
	case ' ':
	case '\t':
		break;
	default:
		return false;
	}

	pos++;
	while( aStr[pos])
	{
		switch(aStr[pos])
		{
			case ' ':
			case '\t':
				pos++;
			break;
			default:
				aTill = pos;
				return true;
		}

	}
	aTill = pos;
	return true;
}

/**
This function returns true if the string starts with non-whitespace.
It also updates the length of this word.
@param aStr  - Line Token
@param aTill - Length of the word
Return Value - True, if the string starts with non-whitespace chars.
It also updates the length of the word.
@internalComponent
@released
*/
bool LineToken::IsWord(char *aStr, int &aTill)
{
	int pos = 0;
	switch( aStr[pos] )
	{
	case '\0':
	case ' ':
	case '\t':
	case '\r':
	case '\n':
		return false;
	default:
		break;
	}

	pos++;
	while( aStr[pos])
	{
		switch(aStr[pos])
		{
			case ' ':
			case '\t':
			case '\r':
			case '\n':
				aTill = pos;
				return true;
			default:
				pos++;
				break;
		}

	}
	aTill = pos;
	return true;
}

/**
This function increments the current offset.
@param aOff  - increment by this value
@internalComponent
@released
*/
void LineToken::IncrOffset(int aOff)
{ 
	iOffset += aOff;
}

/**
This function sets the state of the tokenizer that is parsing 
the line.
@param aState  - next state
@internalComponent
@released
*/
void LineToken::SetState(DefStates aState)
{
	iState = aState;
}

/**
Function to Read def file and get the internal representation in structure.
@param defFile - DEF File name
@internalComponent
@released
*/
SymbolList* DefFile::ReadDefFile(char *defFile)
{
	char *defFileEntries;

	defFileEntries=OpenDefFile(defFile);
	ParseDefFile(defFileEntries);

	delete [] defFileEntries;//Free the memory which was required to read def file

	return iSymbolList;

}

/**
Function to get the internal representation of Def File.
@param defFile - DEF File name
@internalComponent
@released
*/
SymbolList* DefFile::GetSymbolEntryList(char *defFile)
{
	if(iSymbolList)
	{
		return iSymbolList;
	}
	else
	{
		iSymbolList=ReadDefFile(defFile);
		return iSymbolList;
	}

}

/**
Function to write DEF file from symbol entry List.
@param fileName - Def file name
@param newSymbolList - pointer to SymbolList which we get as an input for writing in DEF File
@internalComponent
@released
*/
void DefFile::WriteDefFile(char *fileName, SymbolList * newSymbolList)
{

	char ordinal[6];
	int newDefEntry=0;
	FILE *fptr;

	if((fptr=fopen(fileName,"wb"))==NULL)
	{
		throw FileError(FILEOPENERROR,fileName);
	}
	else
	{
		SymbolList::iterator aItr = newSymbolList->begin();
		SymbolList::iterator last = newSymbolList->end();
		Symbol *aSym;

		fputs("EXPORTS",fptr);
		fputs("\r\n",fptr);
		while( aItr != last)
		{
			aSym = *aItr;
			//Do not write now if its a new entry
			if(aSym->GetSymbolStatus()==New)
			{
				newDefEntry=1;
				aItr++;
				continue;
			}

			//Make it comment if its missing def entry
			if(aSym->GetSymbolStatus()==Missing)
				fputs("; MISSING:",fptr);

			fputs("\t",fptr);
			if((aSym->ExportName()) && strcmp(aSym->SymbolName(),aSym->ExportName())!=0)
			{
				fputs(aSym->ExportName(),fptr);
				fputs("=",fptr);
			}
			fputs(aSym->SymbolName(),fptr);
			fputs(" @ ",fptr);
			sprintf(ordinal,"%d",aSym->OrdNum());
			fputs(ordinal,fptr);
			fputs(" NONAME",fptr);
			if(aSym->CodeDataType()==SymbolTypeData) {
				fputs(" DATA",fptr);
				fputs(" ",fptr);
				char aSymSize[16];
				sprintf(aSymSize, "%d", aSym->SymbolSize());
				fputs(aSymSize,fptr);
			}
			if(aSym->R3unused())
				fputs(" R3UNUSED",fptr);
			if(aSym->Absent())
				fputs(" ABSENT",fptr);
				
			if(aSym->Comment()!=NULL)
			{
				fputs(" ; ",fptr);
				fputs(aSym->Comment(),fptr);
			}
			fputs("\r\n",fptr);
			aItr++;
		}

		//This is for writing new def entry in DEF File
		if(newDefEntry)
		{
			fputs("; NEW:",fptr);
			fputs("\r\n",fptr);
			aItr = newSymbolList->begin();
			last = newSymbolList->end();

			while( aItr != last)
			{
				aSym = *aItr;
				if(aSym->GetSymbolStatus()!=New)
				{
					aItr++;
					continue;
				}
				fputs("\t",fptr);
				if((aSym->ExportName()) && strcmp(aSym->SymbolName(),aSym->ExportName())!=0)
				{
					fputs(aSym->ExportName(),fptr);
					fputs("=",fptr);
				}
				fputs(aSym->SymbolName(),fptr);
				fputs(" @ ",fptr);
				sprintf(ordinal,"%d",aSym->OrdNum());
				fputs(ordinal,fptr);
				fputs(" NONAME",fptr);

				if(aSym->CodeDataType()==SymbolTypeData) {
					fputs(" DATA",fptr);
					fputs(" ",fptr);
					char aSymSize[16];
					sprintf(aSymSize, "%d", aSym->SymbolSize());
					fputs(aSymSize,fptr);
				}

				if(aSym->R3unused())
					fputs(" R3UNUSED",fptr);
				if(aSym->Absent())
					fputs(" ABSENT",fptr);

				if(aSym->Comment()!=NULL)
				{
					if(aSym->CodeDataType()!=SymbolTypeCode &&
						aSym->CodeDataType()!=SymbolTypeData)
					{
						fputs(" ; ",fptr);
						fputs(aSym->Comment(),fptr);
					}
					else
					{
						fputs(" ",fptr);
						fputs(aSym->Comment(),fptr);
					}
				}
				fputs("\r\n",fptr);
				aItr++;
			}
		}
		fputs("\r\n",fptr);
		fclose(fptr);
	}
}