/***********************************************************************
 *  avrp - Atmel AVR programming software to use with Atmel's
 *         serial-port programmers.
 *  Copyright (C) 1997-1998 Jon Anders Haugum
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; see the file COPYING.  If not, write to
 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *
 *
 *  Author of avrp can be reached at:
 *     email: jonah@colargol.tihlde.hist.no
 *     www: http://www.colargol.tihlde.hist.no/~jonah/el/avrp.html
 *     Postal address: Jon Anders Haugum
 *                     Øvre Møllenbergsgt 52
 *                     7014 Trondheim
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "avrp.h"


struct DataFile *OpenDataFile(char *FileName)
	{
	int ok = False;
	struct DataFile *DataFile;
	unsigned char buff[8] = {0};

	DataFile = (struct DataFile *)malloc(sizeof(struct DataFile));
	if(DataFile)
		{
		DataFile->FP = fopen(FileName, "r");
		if(DataFile->FP)
			{
			DataFile->FileType = FILETYPE_UNKNOWN;
			fgets(buff, 8, DataFile->FP);
			fseek(DataFile->FP, 0, SEEK_SET);
			if(buff[0] == ':')
				{
				printf("(Filetype seems to be Intel Hex)\n");
				DataFile->FileType = FILETYPE_INTEL_HEX8M;
				}
			else if((buff[6] == ':') || (buff[4] == ':'))
				{
				printf("(Filetype seems to be Atmel generic)\n");
				DataFile->FileType = FILETYPE_ATMEL_GENERIC;
				}
			if(DataFile->FileType == FILETYPE_UNKNOWN)
				printf("\nError: Unknown filetype!\n");
			else
				ok = True;
			}
		else
			{
			printf("\n");
			perror(FileName);
			}
		}
	else
		printf("\nError: Unable to allocate memory\n");
	if(!ok)
		{
		CloseDataFile(DataFile);
		DataFile = NULL;
		}
	return(DataFile);
	}


void CloseDataFile(struct DataFile *DataFile)
	{
	if(DataFile->FP) fclose(DataFile->FP);
	free(DataFile);
	}


enum
	{
	PART_NONE = 0,
	PART_CHIP,
	PART_VENDOR,
	PART_FAMILY,
	PART_ARCHITECTURES,
	PART_FUSE,
	PART_LOCK
	};

int ReadDefFile(struct ProgramInfo *PI)
	{
	int ok = False, loopok, part = PART_NONE, i, j, ver = 0, rev = 0, first_lockline;
	char Buff[256], *temp;
	FILE *FP;
	struct ChipNode *CN, **LastCN = &PI->FirstChipNode;
	struct VendorNode *VN, **LastVN = &PI->FirstVendorNode;
	struct FamilyNode *FamN, **LastFamN = &PI->FirstFamilyNode;
	struct ArchNode *AN, **LastAN = &PI->FirstArchNode;
	struct FuseNode *FuseN = NULL, **LastFuseN = &PI->FirstFuseNode;
	struct FuseBitNode *FBN, **LastFBN;
	struct LockNode *LN = NULL, **LastLN = &PI->FirstLockNode;
	struct LockBitNode *LBN, **LastLBN;

	FP = fopen((char *)GET_ARG(PI->args, ARG_DEFFILE), "r");
	if(FP)
		{
		loopok = True;
		ok = True;
		while(loopok && ok)
			{
			if(fgets(Buff, 256, FP))
				{
				for(i = 0; (Buff[i] == ' ') || (Buff[i] == 9);) i++;
				if((Buff[i] != ';') && (Buff[i] != 10) && (Buff[i] != 13))
					{
					if(ver == 0)
						{
						if(!strncmp("AVRP.DEF", &Buff[i], 8))
							{
							i += 8;
							while((Buff[i] == ' ') || (Buff[i] == 9)) i++;
							j = i;
							while(isdigit(Buff[i])) i++;
							if(Buff[i] == '.')
								{
								Buff[i++] = '\0';
								rev = atoi(GetNextString(Buff, &i));
								}
							else
								Buff[i] = '\0';
							ver = atoi(&Buff[j]);
							if(ver < DEFFILEVERSION)
								{
								printf("Error: %s: Found file version %d, and it should be version %d\n"
										 "       You should update %s\n",
								       (char *)GET_ARG(PI->args, ARG_DEFFILE), ver, DEFFILEVERSION, (char *)GET_ARG(PI->args, ARG_DEFFILE));
								ok = False;
								}
							else if(ver > DEFFILEVERSION)
								{
								printf("Error: %s: Found file version %d, and it should be version %d\n"
										 "       You should update the avrp program\n",
								       (char *)GET_ARG(PI->args, ARG_DEFFILE), ver, DEFFILEVERSION);
								ok = False;
								}
							else if(rev < DEFFILEREVISION)
								{
								printf("Error: %s: Found file version %d.%d, and it should be version %d.%d or higher\n"
										 "       You should update %s\n",
								       (char *)GET_ARG(PI->args, ARG_DEFFILE), ver, rev, DEFFILEVERSION, DEFFILEREVISION, (char *)GET_ARG(PI->args, ARG_DEFFILE));
								ok = False;
								}
							}
						}
					else if(!strncmp("#END", &Buff[i], 4))
						part = PART_NONE;
					else if(!strncmp("#CHIPS", &Buff[i], 6))
						part = PART_CHIP;
					else if(!strncmp("#VENDORS", &Buff[i], 8))
						part = PART_VENDOR;
					else if(!strncmp("#FAMILIES", &Buff[i], 9))
						part = PART_FAMILY;
					else if(!strncmp("#ARCHITECTURES", &Buff[i], 14))
						part = PART_ARCHITECTURES;
					else if(!strncmp("#FUSES", &Buff[i], 6))
						part = PART_FUSE;
					else if(!strncmp("#LOCKS", &Buff[i], 6))
						part = PART_LOCK;
					else
						{
						if(part == PART_NONE);
						else if(part == PART_CHIP)
							{
							CN = (struct ChipNode *)malloc(sizeof(struct ChipNode));
							if(!CN) goto shit;
							CN->Next = NULL;
							CN->Name = NULL;
							CN->VendorNode = NULL;
							CN->FamilyNode = NULL;
							CN->FuseNode = NULL;
							CN->LockNode = NULL;
							CN->Supported = False;
							temp = GetNextString(Buff, &i);
							CN->Name = malloc(strlen(temp) + 1);
							if(!CN->Name) goto shit;
							strcpy(CN->Name, temp);
							CN->Code = atox(GetNextString(Buff, &i) + 2);
							CN->EepromSize = atoi(GetNextString(Buff, &i));
							CN->Sig = atox(GetNextString(Buff, &i) + 2);
							CN->FuseType = atoi(GetNextString(Buff, &i));
							CN->LockType = atoi(GetNextString(Buff, &i));
							*LastCN = CN;
							LastCN = &CN->Next;
							}
						else if(part == PART_VENDOR)
							{
							VN = (struct VendorNode *)malloc(sizeof(struct VendorNode));
							if(!VN) goto shit;
							VN->Next = NULL;
							VN->Name = NULL;
							VN->Code = atox(GetNextString(Buff, &i) + 2);
							temp = GetNextString(Buff, &i);
							VN->Name = malloc(strlen(temp) + 1);
							if(!VN->Name) goto shit;
							strcpy(VN->Name, temp);
							*LastVN = VN;
							LastVN = &VN->Next;
							}
						else if(part == PART_FAMILY)
							{
							FamN = (struct FamilyNode *)malloc(sizeof(struct FamilyNode));
							if(!FamN) goto shit;
							FamN->Next = NULL;
							FamN->Name = NULL;
							FamN->ArchNode = NULL;
							FamN->Code = atox(GetNextString(Buff, &i) + 2);
							temp = GetNextString(Buff, &i);
							FamN->Name = malloc(strlen(temp) + 1);
							if(!FamN->Name) goto shit;
							strcpy(FamN->Name, temp);
							FamN->FlashSize = atoi(GetNextString(Buff, &i));
							*LastFamN = FamN;
							LastFamN = &FamN->Next;
							}
						else if(part == PART_ARCHITECTURES)
							{
							AN = (struct ArchNode *)malloc(sizeof(struct ArchNode));
							if(!AN) goto shit;
							AN->Next = NULL;
							AN->Name = NULL;
							temp = GetNextString(Buff, &i);
							AN->Name = malloc(strlen(temp) + 1);
							if(!AN->Name) goto shit;
							strcpy(AN->Name, temp);
							AN->WordSize = atoi(GetNextString(Buff, &i));
							AN->NeedFlashErase = atoi(GetNextString(Buff, &i));
							*LastAN = AN;
							LastAN = &AN->Next;
							}
						else if(part == PART_FUSE)
							{
							if(!strncmp(&Buff[i], "#DEFFUSE", 8))
								{
								FuseN = (struct FuseNode *)malloc(sizeof(struct FuseNode));
								if(!FuseN) goto shit;
								FuseN->Next = NULL;
								LastFBN = &FuseN->FirstFuseBitNode;
								i += 8;
								FuseN->Num = atoi(GetNextString(Buff, &i));
								*LastFuseN = FuseN;
								LastFuseN = &FuseN->Next;
								}
							else if(!strncmp(&Buff[i], "#DEFEND", 7))
								FuseN = NULL;
							else if(FuseN)
								{
								FBN = (struct FuseBitNode *)malloc(sizeof(struct FuseBitNode));
								if(!FBN) goto shit;
								FBN->Next = NULL;
								FBN->ShortName = NULL;
								FBN->LongName = NULL;
								temp = GetNextString(Buff, &i);
								FBN->ShortName = malloc(strlen(temp) + 1);
								if(!FBN->ShortName) goto shit;
								strcpy(FBN->ShortName, temp);
								FBN->BitNum = atoi(GetNextString(Buff, &i));
								temp = GetNextString(Buff, &i);
								FBN->LongName = malloc(strlen(temp) + 1);
								if(!FBN->LongName) goto shit;
								strcpy(FBN->LongName, temp);
								*LastFBN = FBN;
								LastFBN = &FBN->Next;
								}
							}
						else if(part == PART_LOCK)
							{
							if(!strncmp(&Buff[i], "#DEFLOCK", 8))
								{
								first_lockline = True;
								LN = (struct LockNode *)malloc(sizeof(struct LockNode));
								if(!LN) goto shit;
								LN->Next = NULL;
								LastLBN = &LN->FirstLockBitNode;
								i += 8;
								LN->Num = atoi(GetNextString(Buff, &i));
								*LastLN = LN;
								LastLN = &LN->Next;
								}
							else if(!strncmp(&Buff[i], "#DEFEND", 7))
								LN = NULL;
							else if(LN)
								{
								if(first_lockline)
									{
									first_lockline = False;
									LN->NumberOfBits = atoi(GetNextString(Buff, &i));
									LN->WriteBits = 0;
									for(j = 0; j < LN->NumberOfBits; j++)
										LN->WriteBits |= atoi(GetNextString(Buff, &i)) << (j * 4);
									LN->ReadBits = 0;
									for(j = 0; j < LN->NumberOfBits; j++)
										LN->ReadBits |= atoi(GetNextString(Buff, &i)) << (j * 4);
									}
								else
									{
									LBN = (struct LockBitNode *)malloc(sizeof(struct LockBitNode));
									if(!LBN) goto shit;
									LBN->Next = NULL;
									LBN->LongName = NULL;
									LBN->Mode = atoi(GetNextString(Buff, &i));
									LBN->Mask = 0;
									for(j = 0; j < LN->NumberOfBits; j++)
										LBN->Mask |= atoi(GetNextString(Buff, &i)) << j;
									temp = GetNextString(Buff, &i);
									LBN->LongName = malloc(strlen(temp) + 1);
									if(!LBN->LongName) goto shit;
									strcpy(LBN->LongName, temp);
									*LastLBN = LBN;
									LastLBN = &LBN->Next;
									}
								}
							}
						}
					}
				}
			else
				{
				loopok = False;
				if(!feof(FP))
					{
					ok = False;
					perror((char *)GET_ARG(PI->args, ARG_DEFFILE));
					}
				}
			}
		if(ver == 0)
			{
			ok = False;
			printf("Error: %s: No version string found\n",
			       (char *)GET_ARG(PI->args, ARG_DEFFILE));
			}
		fclose(FP);
		}
	else
		{
		perror((char *)GET_ARG(PI->args, ARG_DEFFILE));
		printf("You should check if avrp.def is properly installed\n");
		}
	return(ok);

shit:
	printf("Error: Unable to allocate memory\n");
	fclose(FP);
	return(False);
	}


char *GetNextString(char *Buff, int *index)
	{
	int i;

	while((Buff[*index] == ' ') || (Buff[*index] == 9))
		(*index)++;
	if(Buff[*index] == '\"')
		{
		i = ++(*index);
		while((Buff[*index] != '\"') && (Buff[*index] != 13) && (Buff[*index] != 10))
			(*index)++;
		Buff[(*index)++] = '\0';
		}
	else
		{
		i = *index;
		while((Buff[*index] != ' ') && (Buff[*index] != 9) && (Buff[*index] != 13) && (Buff[*index] != 10))
			(*index)++;
		Buff[(*index)++] = '\0';
		}
	return(&Buff[i]);
	}
