/* Cheat Database Converter : RAINE 0.32a -> MAME 37B16 */
/* Coded by JCK from The Ultimate Patchers              */
/* Version 1.0B - Release date : 19th of July 2001      */

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

#ifdef __linux__
#define stricmp strcasecmp
#endif

#define MAXLINELENGTH	2048
#define MAXCHEATS		256

struct cheat_struct
{
	char Game[9];
	int  Cpu;
	int  Addr;
	int  Data;
	int  Mask;
	int  Type;
	char Name[MAXLINELENGTH];
	char More[MAXLINELENGTH];
} Cheat;


void DisplayHelp(char *ProgName)
{
  printf("Syntax : %s <CheatFileIn> <CheatFileOut> <GameName>\n\n", ProgName);
}

int ExistFile(char *FileName)
{
  FILE *F;

  F = fopen(FileName,"r");
  if (!F)    /* If the file doesn't exist .... */
	return(0);
  else
  {
	fclose(F);
	printf("\nFile '%s' already exists ! ", FileName);
	printf("Do you want to overwrite it (y = YES) ? ");
	return(toupper(getchar()) == 'Y' ? 0 : 1);
  }
}

int GetData(struct cheat_struct Cheat)
{
  int Data;

  if (Cheat.Type & 0x10)				/* Watch cheat */
  {
	Data = 0;
  }
  else if (Cheat.Type & 0x04)				/* Bit-related cheat */
  {
	Data = (Cheat.Data ? Cheat.Data : Cheat.Mask);
  }
  else
  {
	Data = Cheat.Data;
  }
  
  return (Data);
}

int GetType(struct cheat_struct Cheat)
{
  int Type;

  if (Cheat.Type & 0x10)				/* Watch cheat */
  {
	Type = 998;
  }
  else if (Cheat.Type & 0x04)				/* Bit-related cheat */
  {
	Type = (Cheat.Data ? 20 : 40);
  }
  else
  {
	Type = 0;
  }

  if ((Cheat.Type & 0x08) && (Type != 998))	/* Temporary cheat */
  {
	Type++;
  }
  
  return (Type);
}

int main(int argc, char **argv)
{
  FILE *FI;
  FILE *FO;
  char *ptr;
  char SI[MAXLINELENGTH];
  char SO[MAXLINELENGTH];
  char fmt[40];
  char CFI[80] = "";
  char CFO[80] = "";
  char GN[9] = "";
  int  Count = 0;

  int  AddMore;		/* For extra description */

  if (2 <= argc)    /* Copy the 1st parameter if it exists */
	strcpy(CFI, argv[1]);

  if (3 <= argc)    /* Copy the 2nd parameter if it exists */
	strcpy(CFO, argv[2]);

  if (4 <= argc)    /* Copy the 3rd parameter if it exists and convert it */
  {
	int i;

	strcpy(GN, argv[3]);
	for (i = 0; i < strlen(GN); i ++)
		GN[i] = (unsigned char)tolower(GN[i]);
  }

  if ((!CFI[0]) || (!CFO[0]) || (!GN[0]))    /* Wrong number of arguments */
  {
	DisplayHelp(argv[0]);
	return(99);
  }

  if (!stricmp(CFI, CFO))
  {
	printf("Input and Output files must have a different name !\n\n");
	return(1);
  }

  FI = fopen(CFI,"r");    /* Open 1st file for input */

  if (!FI)
  {
	printf("\nUnable to read '%s' !\n\n", CFI);
	return(2);
  }

  FO = fopen(CFO,"a+");    /* Open 2nd file for output (append) */

  if (!FO)
  {
	printf("\nUnable to write '%s' !\n\n", CFO);
	return(3);
  }

  Cheat.Game[0] = 0;
  printf("\nAdding cheats for game '%s' in '%s' into '%s' .... ", GN, CFI, CFO);
  for(;;)
  {
	if (fgets(SI, MAXLINELENGTH, FI) == NULL)
		break;

	if ((!SI[0]) || (SI[0] == '\n'))		/* Ignore empty lines */
		continue;

	if (SI[0] == '#')					/* Ignore comment lines */
		continue;

	if (SI[0] == '[')
	{
		strcpy(SI,&SI[1]);
		ptr = strtok(SI, ":");			/* Extract the name of the game */
		strcpy (Cheat.Game, ptr);
		continue;
	}

	if (!strcmp(GN, Cheat.Game))			/* Compare the names of the game */
	{
		ptr = strtok(SI, "=");			/* Extract "Cheatxx " */
		ptr += 2;					/* Skip "= " */
		ptr = strtok(NULL, ":");		/* Extract the address */
		sscanf(ptr,"%x", &Cheat.Addr);
		ptr = strtok(NULL, ":");		/* Extract the byte to poke */
		sscanf(ptr,"%x", &Cheat.Data);
		ptr = strtok(NULL, ":");		/* Extract the mask */
		sscanf(ptr,"%x", &Cheat.Mask);
		ptr = strtok(NULL, ":");		/* Extract the type of cheat */
		sscanf(ptr,"%x", &Cheat.Type);
		ptr = strtok(NULL, ":");		/* Extract the description */
		strcpy(Cheat.Name,ptr);
		strcpy(Cheat.More,"\n");
		ptr = strtok(NULL, ":");
		if (ptr)
			strcpy(Cheat.More,ptr);		/* Extract the extra description */
		if (strstr(Cheat.Name,"\n") != NULL)
			Cheat.Name[strlen(Cheat.Name)-1] = 0;
		if (strstr(Cheat.More,"\n") != NULL)
			Cheat.More[strlen(Cheat.More)-1] = 0;

      	Cheat.Cpu = 0;

		AddMore = (Cheat.More[0]);

		strcpy (fmt, "%s:%d:%X:%02X:%03d:%s");	/* Formatting output */

		if (Cheat.Type & 0x03)
			strcat (fmt," (%d/%d)");

		if (AddMore)
			strcat (fmt,":%s");

		strcat (fmt, "\n");

		switch (Cheat.Type & 0x03)
		{
			case 0 :
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 0,
							(GetData(Cheat) >> 0) & 0xff,
							(GetType(Cheat) + 0),
							Cheat.Name, (AddMore ? Cheat.More : ""));
				Count++;
				break;
			case 1 :
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 0,
							(GetData(Cheat) >> 8) & 0xff,
							(GetType(Cheat) + 0),
							Cheat.Name, 1, 2, (AddMore ? Cheat.More : ""));
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 1,
							(GetData(Cheat) >> 0) & 0xff,
							(GetType(Cheat) + 500),
							Cheat.Name, 2, 2, (AddMore ? Cheat.More : ""));
				Count += 2;
				break;
			case 2 :
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 0,
							(GetData(Cheat) >> 16) & 0xff,
							(GetType(Cheat) + 0),
							Cheat.Name, 1, 3, (AddMore ? Cheat.More : ""));
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 1,
							(GetData(Cheat) >> 8) & 0xff,
							(GetType(Cheat) + 500),
							Cheat.Name, 2, 3, (AddMore ? Cheat.More : ""));
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 2,
							(GetData(Cheat) >> 0) & 0xff,
							(GetType(Cheat) + 500),
							Cheat.Name, 3, 3, (AddMore ? Cheat.More : ""));
				Count += 3;
				break;
			case 3 :
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 0,
							(GetData(Cheat) >> 24) & 0xff,
							(GetType(Cheat) + 0),
							Cheat.Name, 1, 4, (AddMore ? Cheat.More : ""));
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 1,
							(GetData(Cheat) >> 16) & 0xff,
							(GetType(Cheat) + 500),
							Cheat.Name, 2, 4, (AddMore ? Cheat.More : ""));
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 2,
							(GetData(Cheat) >> 8) & 0xff,
							(GetType(Cheat) + 500),
							Cheat.Name, 3, 4, (AddMore ? Cheat.More : ""));
				fprintf (FO, fmt, GN, Cheat.Cpu, Cheat.Addr + 3,
							(GetData(Cheat) >> 0) & 0xff,
							(GetType(Cheat) + 500),
							Cheat.Name, 4, 4, (AddMore ? Cheat.More : ""));
				Count += 4;
				break;
		}
	}
  }

  if (Count)
	fprintf(FO, "\n");

  fclose(FI);
  fclose(FO);

  printf ("\n%d cheat codes have been added.\n\n", Count); 

  return(0);
}
