/****************************************************************/
/*								*/
/* Sub.c - this file includes some subroutines for GALer	*/
/*								*/
/* 								*/
/****************************************************************/



#include <dos/dostags.h>

#include <exec/types.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/reqtools.h>
#include <libraries/gadtools.h>
#include <libraries/locale.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <proto/locale.h>
#include <proto/reqtools.h>
#include <proto/gadtools.h>
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>

#include "GALer.h"
#include "Localize.h"


#define	YES_GADID	1
#define	NO_GADID	2


#define GD_AsmGad01     1		/* GadgetIDs für Assembler */
#define GD_AsmGad02	2
#define GD_AsmGad03	3
#define GD_AsmGad04	4
#define GD_AsmGad05	5
#define GD_AsmGad06	6
#define GD_AsmGad07	7
#define GD_AsmGad08	8



#define GD_WriteGad01	1		/* GadgetIDs für Schreibverhalten */
#define GD_WriteGad02	2
#define GD_WriteGad03	3
#define GD_WriteGad04	4
#define GD_WriteGad05	5
#define GD_WriteGad06	6



#define GD_JParGad01	1		/* GadgetIDs für JEDEC-Parameter */
#define GD_JParGad02	2
#define GD_JParGad03	3	
#define GD_JParGad04	4


#define GD_SelEdGad01	1		/* GadgetIDs of select editor */
#define GD_SelEdGad02	2
#define GD_SelEdGad03	3	




extern	struct  AppString { LONG   as_ID;
		 	    STRPTR as_Str;
			  };

extern	struct  AppString AppStrings[];

extern	struct	Screen	 *screen;
extern	struct	Window	 *window;
extern	struct	RastPort *rp;
extern	struct	Menu	 *mainmenu;
extern	struct	TextAttr topaz8;
extern	struct	Gadget	 *WriteGList, *JEDGList, *AsmGList;
extern	struct	Gadget	 *SelectEditorGList;
extern	struct  Gadget	 *SelectEditorGadgets[];
extern	struct	Catalog	 *catalog;



extern	struct	rtFileRequester	*filereq;

extern	APTR	VisualInfo;


extern	int	GALType, MaxFuseAdr, RowSize, XORSize, SigAdr;
extern	int	hw_version;

extern	UBYTE	title[];




						/*Voreinstellungen*/
struct	Configuration Config = { GAL16V8,	/*GAL16V8*/
				 YES,		/*Requester für Typ*/
				 YES,		/*Jedec erzeugen*/
				 NO,		/*kein Fuse-File*/
				 NO,		/*kein Chip-File*/
				 NO,		/*kein Pin-File*/
				 NO,		/*kein Auto-Save*/
				 YES,		/*autom. GALTyp einstellen*/
				 YES,		/*Leertest vor GAL-Prog.*/
				 YES,		/*Verify nach GAL-Prog.*/
				 YES,		/*Leertest vor Copy-GAL*/
				 YES,		/*Verify nach Copy-GAL*/
				 YES,		/*Leertest nach GAL-Löschen*/
				 NO,		/*Sec.Bit der Jedec-Datei*/
				 YES,		/*Fuse-Checksumme der Jedec*/
				 NO,		/*File-Checksumme der Jedec*/
				 HW_GALER_1_3,	/*Hardware-Version*/
				 YES,		/*WB to front*/
				 "c:ed \"%s\" -STICKY"
			    		};



struct	Configuration DummyConfig;		/*für LoadConfig*/




UBYTE	ErrorLineStr[22];







struct	IntuiText WriteIText3 =	{ 2, 0, JAM1, 11, 83, &topaz8, NULL, NULL };

struct	IntuiText WriteIText2 =	{ 2, 0, JAM1, 11, 44, &topaz8, NULL,
				  &WriteIText3 };

struct	IntuiText WriteIText1 = { 2, 0, JAM1, 11,  5, &topaz8, NULL,
				  &WriteIText2 };



struct IntuiText AsmITxt1 = { 2, 0, JAM1, 16, 6, &topaz8, NULL, NULL };


struct IntuiText JEDITxt1 = { 2, 0, JAM1,  3, 7, &topaz8, NULL, NULL };





					/* Gadgets für Assembler-Window */

struct NewGadget AsmNGad[] = {
	60, 17, 26, 11, NULL, NULL, GD_AsmGad01, PLACETEXT_RIGHT, NULL, NULL,
	60, 29, 26, 11, NULL, NULL, GD_AsmGad02, PLACETEXT_RIGHT, NULL, NULL,
	60, 41, 26, 11, NULL, NULL, GD_AsmGad03, PLACETEXT_RIGHT, NULL, NULL,
	60, 53, 26, 11, NULL, NULL, GD_AsmGad04, PLACETEXT_RIGHT, NULL, NULL,
	60, 73, 26, 11, NULL, NULL, GD_AsmGad05, PLACETEXT_RIGHT, NULL, NULL,
	19, 93, 26, 11, NULL, NULL, GD_AsmGad06, PLACETEXT_RIGHT, NULL, NULL,
	19, 118, 83, 14, NULL, NULL, GD_AsmGad07, PLACETEXT_IN, NULL, NULL,
	178, 118, 83, 14, NULL, NULL, GD_AsmGad08, PLACETEXT_IN, NULL, NULL
};


UWORD AsmGTypes[] = {
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	BUTTON_KIND,
	BUTTON_KIND
};


ULONG AsmGTags[] = {
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(TAG_DONE),
	(TAG_DONE)
};





					/* Gadgets für Schreibverhalten */
UWORD WriteGTypes[] = {
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	BUTTON_KIND
};

struct NewGadget WriteNGad[] = {
	36, 15, 26, 11, NULL, NULL, GD_WriteGad01, PLACETEXT_RIGHT, NULL, NULL,
	36, 27, 26, 11, NULL, NULL, GD_WriteGad02, PLACETEXT_RIGHT, NULL, NULL,
	36, 54, 26, 11, NULL, NULL, GD_WriteGad03, PLACETEXT_RIGHT, NULL, NULL,
	36, 66, 26, 11, NULL, NULL, GD_WriteGad04, PLACETEXT_RIGHT, NULL, NULL,
	36, 93, 26, 11, NULL, NULL, GD_WriteGad05, PLACETEXT_RIGHT, NULL, NULL,
	68, 118, 79, 14, NULL, NULL, GD_WriteGad06, PLACETEXT_IN, NULL, NULL
};

ULONG WriteGTags[] = {
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(TAG_DONE)
};





					/* Gadgets für JEDEC-Parameter */
UWORD JEDGTypes[] = {
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	CHECKBOX_KIND,
	BUTTON_KIND
};


struct NewGadget JEDNGad[] = {
	20, 17, 26, 11, NULL, NULL, GD_JParGad01, PLACETEXT_RIGHT, NULL, NULL,
	20, 29, 26, 11, NULL, NULL, GD_JParGad02, PLACETEXT_RIGHT, NULL, NULL,
	20, 41, 26, 11, NULL, NULL, GD_JParGad03, PLACETEXT_RIGHT, NULL, NULL,
	56, 64, 76, 13, NULL, NULL, GD_JParGad04, PLACETEXT_IN, NULL, NULL
};


ULONG JEDGTags[] = {
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(TAG_DONE)
};



					/* gadgets for SelectEditor */
UWORD SelectEditorGTypes[] = {
	STRING_KIND,
	CHECKBOX_KIND,
	BUTTON_KIND
};

struct NewGadget SelectEditorNGad[] = {
	76,  8, 149, 14, NULL, NULL, GD_SelEdGad01, PLACETEXT_LEFT, NULL, NULL,
	76,  30, 26, 11, NULL, NULL, GD_SelEdGad02, PLACETEXT_RIGHT, NULL, NULL,
	115, 55, 63, 14, NULL, NULL, GD_SelEdGad03, PLACETEXT_IN, NULL, NULL
};

ULONG SelectEditorGTags[] = {
	(GTST_String), NULL, (GTST_MaxChars), EDITOR_STR_SIZE, (TAG_DONE),
	(GTCB_Checked), FALSE, (TAG_DONE),
	(TAG_DONE)
};





char	filename[108];				/* Puffer für Filenamen */
char	path[108 + 130 + 4];			/* Puffer für Dir+File  */
						/* +4 für Suffix	*/

char	prevSourceFile[108 + 130 + 4];		/* name of the prev. */
						/* assembled file */











/* Schreibverhalten: Läßt Requester erscheinen, in dem eingestellt werden
		     kann, ob ein Leertest und/oder Verify nach einem
		     schreibenden Zugriff auf ein GAL gemacht werden soll.
   Aufruf   : Schreibverhalten();
   Parameter: ---
   Ergebnis : --- 
*/
void Schreibverhalten(void)
{
struct	Window 	        *writewin;
struct	IntuiMessage	*imsg;
ULONG	class;
USHORT	code, gadID;
UWORD   offx = screen->WBorLeft, offy = screen->WBorTop + screen->RastPort.TxHeight + 1;



  if (!(writewin = OpenWindowTags( NULL,
				WA_Left,	 207,
				WA_Top,		 25,
				WA_Width,	 226,
				WA_Height,	 142 + offy,
				WA_IDCMP,	 CHECKBOXIDCMP|BUTTONIDCMP|IDCMP_REFRESHWINDOW|IDCMP_VANILLAKEY,
				WA_Flags,	 WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
				WA_Gadgets,	 WriteGList,
				WA_Title,	 AppStrings[MSG_WRITEACC_WIN].as_Str,
				WA_CustomScreen, screen,
				TAG_DONE )))
    return;


  GT_RefreshWindow(writewin, NULL);


  offx = writewin->BorderLeft;
  offy = writewin->BorderTop;
  PrintIText(writewin->RPort, &WriteIText1, offx, offy);



  for (;;) {

    Wait (1 << writewin->UserPort->mp_SigBit);

    while (imsg = GT_GetIMsg(writewin->UserPort)) {

      class = imsg->Class;
      code  = imsg->Code;

      if (class == GADGETUP)
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

      GT_ReplyIMsg(imsg);


      if (class == VANILLAKEY) {
	if (code == 13) {			/* Return-Key = Weiter */
	  CloseWindow(writewin);
	  return;
	}
      }

      if (class == GADGETUP) {
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

	switch (gadID) {

	  case GD_WriteGad06:
		CloseWindow(writewin);
		return;

	  case GD_WriteGad01:
		Config.ProgEmptyTest = !Config.ProgEmptyTest;
		break;

	  case GD_WriteGad02:
		Config.ProgVerify = !Config.ProgVerify;
		break;

	  case GD_WriteGad03:
		Config.CopyEmptyTest = !Config.CopyEmptyTest;
		break;

	  case GD_WriteGad04:
		Config.CopyVerify = !Config.CopyVerify;
		break;

	  case GD_WriteGad05:
		Config.EraseEmptyTest = !Config.EraseEmptyTest;
		break;

	}
      }
    }
  }
}



/* JedecRequester: Läßt Requester erscheinen, in dem eingestellt werden kann,
	     was wie im JEDEC-File stehen soll.
   Aufruf   : JedecReq();
   Parameter: ---
   Ergebnis : --- 
*/
void JedecRequester(void)
{
struct	Window 	        *jedwin;
struct	IntuiMessage	*imsg;
ULONG	class;
USHORT	code, gadID;
UWORD   offx = screen->WBorLeft, offy = screen->WBorTop + screen->RastPort.TxHeight + 1;




  if (!(jedwin = OpenWindowTags( NULL,
				WA_Left,	 220,
				WA_Top,		 45,
				WA_Width,	 200,
				WA_Height,	 84 + offy,
				WA_IDCMP,	 CHECKBOXIDCMP|BUTTONIDCMP|IDCMP_REFRESHWINDOW|IDCMP_VANILLAKEY,
				WA_Flags,	 WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
				WA_Gadgets,	 JEDGList,
				WA_Title,	 AppStrings[MSG_JEDPARA_WIN].as_Str,
				WA_CustomScreen, screen,
				TAG_DONE )))
    return;


  GT_RefreshWindow(jedwin, NULL);


  offx = jedwin->BorderLeft;
  offy = jedwin->BorderTop;
  PrintIText(jedwin->RPort, &JEDITxt1, offx, offy);



  for (;;) {

    Wait (1 << jedwin->UserPort->mp_SigBit);

    while (imsg = GT_GetIMsg(jedwin->UserPort)) {

      class = imsg->Class;
      code  = imsg->Code;

      if (class == GADGETUP)
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

      GT_ReplyIMsg(imsg);


      if (class == VANILLAKEY) {
	if (code == 13) {			/* Return-Key = Weiter */
	  CloseWindow(jedwin);
	  return;
	}
      }

      if (class == GADGETUP) {
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

	switch (gadID) {

	  case GD_JParGad04:
		CloseWindow(jedwin);
		return;

	  case GD_JParGad01:
		Config.JedecSecBit = !Config.JedecSecBit;
		break;

	  case GD_JParGad02:
		Config.JedecFuseChk = !Config.JedecFuseChk;
		break;

	  case GD_JParGad03:
		Config.JedecFileChk = !Config.JedecFileChk;
		break;

	}
      }
    }
  }
}





/* About: zeigt About-Text
   Aufruf   : About();
   Parameter: ---
   Ergebnis : --- 
*/
void About(void)
{

  rtEZRequestTags( AppStrings[MSG_ABOUT_TXT].as_Str,
		   "O.K.", NULL, NULL, RT_ReqPos, REQPOS_CENTERSCR, TAG_END);

}




/* mystrcmp: wie strcmp, aber keine Unterscheidung zwischen Groß- und
   Kleinschreibung
   Aufruf: result = mystrcmp(cptr1, cptr2);
	   cptr1: Zeiger auf 1. String
	   cptr2: Zeiger auf 2. String
   Ergebnis: 
	   result = 1: nicht gleich
	  	  = 0: gleich
*/
int mystrcmp(char *cptr1, char *cptr2)
{
  while (*cptr1 && *cptr2) {
    if (tolower(*cptr1) != tolower(*cptr2))
      return(1);
    cptr1++;
    cptr2++;
   }

  if (!*cptr1 && !*cptr2)
    return(0);
  else
    return(1);
}


/* MyFileReq: öffnet den FileRequester aus der "req.library"
   Aufruf: antwort = MyFileReq((char *)headtxt, (char *)showtxt, int showreq);
   	 	 headtxt: Zeiger auf File-Requester-Titel
		 showtxt: Zeiger auf Suffix
		 showreq: YES: FileRequester zeigen; NO: keinen Requester
   Ergebnis: 1 : O.K. wurde angeklickt
	     0 : Cancel wurde angeklickt
*/
int MyFileReq(char *headtxt, char *showtxt, int showreq, int mode)
{
struct	FileLock *lock;
char	*pos1, *pos2;
int	freq = YES,result;
char	showpattern[10] = "#?";
ULONG	reqtags[] = {RT_ReqPos, REQPOS_CENTERSCR, TAG_END};



  strcat(showpattern ,showtxt);		/* Show-Pattern erzeugen */

  rtChangeReqAttr(filereq, RTFI_MatchPat, showpattern, TAG_END);

					 /*falls vorhanden, Suffix löschen*/
  if (strlen((char *)filename) >= 4) {   /*und "showtxt" anhängen */
    pos1 = (char *)(filename + (long)strlen(filename) - (long)strlen(showtxt));
    if ((!mystrcmp(pos1, ".pld")) || (!mystrcmp(pos1, ".jed")) ||
        (!mystrcmp(pos1, ".pin")) || (!mystrcmp(pos1, ".chp")) ||
        (!mystrcmp(pos1, ".fus"))) {
      *pos1 = 0;
      strcat((char *)&filename[0], showtxt);
    }
  }



  if (showreq)				/*FileRequester zeigen?*/
    freq = (int)rtFileRequest(filereq, filename, headtxt,
			      RT_ReqPos,  REQPOS_CENTERSCR,
			      RTFI_Flags, FREQF_PATGAD, TAG_END);

  if ((showreq && freq) || !showreq) {

    if (strlen((char *)filename) >= 4) {		/*Suffix anhängen*/

      pos1 = (char *)(filename + (long)strlen(filename) - (long)strlen(showtxt));

        if (mystrcmp(pos1, showtxt)) {		/*Suffix nur anhängen, wenn*/
          strcat(filename, showtxt);		/*es nicht schon da steht  */
          strcat(path, showtxt);
	}

    }
    else {

     if (!strlen(filename))			/*kein File angegeben?*/
       return(0);				/*dann Abbruch*/

     strcat(filename, showtxt);
     strcat(path, showtxt);

    }

					    /* Pfad erstellen */
    strcpy(path, filereq->Dir);

    pos1 = (char *)(filereq->Dir + ((long)strlen(filereq->Dir) - 1L));
    pos2 = (char *)(path + ((long)strlen(path)));

    if (!((*pos1 == ':') || (*pos1 == '/') || !*pos1)) {
      *pos2++ = '/';
      *pos2   = 0x00;				/*Stringende*/
    }
    strcat(path, filename);	   


    if (!strcmp(showtxt, ".pld"))		/* copy dir+filename of the */
      strcpy(prevSourceFile, path);		/* source file to buffer */



    if (showreq && (mode == SAVE)) {	/* wenn Requester für's Schreiben, */
					/* dann abfragen of File schon */
					/* existiert */
      if ((lock = (struct FileLock *) Lock((BYTE *)path, (long)ACCESS_READ))) {
	UnLock((BPTR)lock);

        result = rtEZRequest(AppStrings[MSG_SAVEOVER].as_Str,
			     AppStrings[MSG_YESNO_GADS].as_Str, NULL,
			     (struct TagItem *)reqtags, filename);

	if (!result)			/* nochmal File-Requester aufrufen */
	  return(MyFileReq(headtxt, showtxt, showreq, mode));

      }
    }
    return(1);
  }
  else
    return(0);
}






/* MyRequest:
   öffnet einen Requester und wartet auf die Antwort
   Aufruf: antwort = MyRequest(mode,text);
	   mode: CONT_REQ : Requester mit Weiter/Abbruch-Gadgets
		 ERR_REQ  : Requester für Fehlermeldungen (Abbruch/Abbruch)
		 INFO_REQ : Requester für Informationen (Weiter/Weiter)
		 ERASE_REQ: Requester mit Löschen/Abbruch-Gadgets
		 GALTYPE_REQ: Öffnet Requester, in dem der GAL-Typ eingestellt
		   werden kann, falls im Menü "Typ-Requester" eingestellt ist.
		   Wenn dies nicht der Fall ist, dann wird ein normaler	
		   Frage-Requester ("CONT_REQ") ausgegeben.
	   text: Zeiger auf Requester-Text
	   antwort: 0=Abbruch oder Fehler, 1=Bestätigung
		    bei GALTYPE_REQ:   1 = GAL16V8
				       2 = GAL20V8
				       3 = GAL22V10
				       4 = GAL20RA10
*/
int MyRequest(int mode, UBYTE *text)
{
int result;


 if (Config.GALTypeReq && (mode == GALTYPE_REQ)) {	/* GAL-Gadgets? */

   if (hw_version <= HW_GALER_1_2)
     result = (int)rtEZRequestTags(text,
	 	   AppStrings[MSG_TYPE_GADS1].as_Str, NULL, NULL,
		   RT_ReqPos, REQPOS_CENTERSCR, TAG_END);
   else
     result = (int)rtEZRequestTags(text,
	 	   AppStrings[MSG_TYPE_GADS2].as_Str, NULL, NULL,
		   RT_ReqPos, REQPOS_CENTERSCR, TAG_END);

   switch(result) {
     case  0:	return(0);			/* Abbruch angewählt */
		break;

     case  1:	SetGALType(GAL16V8);		/* GAL16V8 angewählt */
		return(1);
		break;

     case  2: SetGALType(GAL20V8);		/* GAL20V8 angewählt */
		return(2);
		break;

     case  3: SetGALType(GAL22V10);		/* GAL22V10 angewählt */
		return(3);
		break;

     case  4: SetGALType(GAL20RA10);		/* GAL20RA10 angewählt */
		return(4);
		break;
   }

 }
 else {

   if (mode == ERASE_REQ)
     return((int)rtEZRequestTags(text,
				 AppStrings[MSG_ERSCNCL].as_Str, NULL, NULL,
				 RT_ReqPos, REQPOS_CENTERSCR, TAG_END));

   if (mode == ERR_REQ)
     return((int)rtEZRequestTags(text,
				 AppStrings[MSG_CANCEL_GAD].as_Str, NULL, NULL,
				 RT_ReqPos, REQPOS_CENTERSCR, TAG_END));


   if ((mode == CONT_REQ) || (mode == GALTYPE_REQ))
     return((int)rtEZRequestTags(text,
				 AppStrings[MSG_CONTCNCLS_GAD].as_Str, NULL, NULL,
				 RT_ReqPos, REQPOS_CENTERSCR, TAG_END));


   if (mode == INFO_REQ)
     return((int)rtEZRequestTags(text,
				 AppStrings[MSG_CONT_GAD].as_Str, NULL, NULL,
				 RT_ReqPos, REQPOS_CENTERSCR, TAG_END));

 }

 return(0);

}




/* AsmRequester: öffnet den Requester mit den Assembler-Optionen
   Parameter: keine
   Ergebnis : 0 : Abbruch
	      1 : Weiter
*/
int AsmRequester(void)
{
struct	Window 	        *asmwin;
struct	IntuiMessage	*imsg;
ULONG	class;
USHORT	code, gadID;
UWORD   offx = screen->WBorLeft, offy = screen->WBorTop + screen->RastPort.TxHeight + 1;




  if (!(asmwin = OpenWindowTags( NULL,
				WA_Left,	 175,
				WA_Top,		 25,
				WA_Width,	 290,
				WA_Height,	 141 + offy,
				WA_IDCMP,	 CHECKBOXIDCMP|BUTTONIDCMP|IDCMP_REFRESHWINDOW|IDCMP_VANILLAKEY,
				WA_Flags,	 WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
				WA_Gadgets,	 AsmGList,
				WA_Title,	 (UBYTE *)"Assembler",
				WA_CustomScreen, screen,
				TAG_DONE )))
    return(0);

  GT_RefreshWindow(asmwin, NULL);


  offx = asmwin->BorderLeft;
  offy = asmwin->BorderTop;
  PrintIText(asmwin->RPort, &AsmITxt1, offx, offy);



  for (;;) {

    Wait (1 << asmwin->UserPort->mp_SigBit);

    while (imsg = GT_GetIMsg(asmwin->UserPort)) {

      class = imsg->Class;
      code  = imsg->Code;

      if (class == GADGETUP)
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

      GT_ReplyIMsg(imsg);


      if (class == VANILLAKEY) {
	if (code == 13) {			/* Return => Weiter */
	  CloseWindow(asmwin);
	  return(1);
	}

	if (code == 0x1B) {			/* ESC => Abbruch */
	  CloseWindow(asmwin);
	  return(0);
        }
      }

      if (class == GADGETUP) {
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

	switch (gadID) {

	  case GD_AsmGad07:
		CloseWindow(asmwin);
		return(1);
		break;

	  case GD_AsmGad08:
		CloseWindow(asmwin);
		return(0);
		break;

	  case GD_AsmGad01:
		Config.GenJedec = !Config.GenJedec;
		break;

	  case GD_AsmGad02:
		Config.GenFuse = !Config.GenFuse;
		break;

	  case GD_AsmGad03:
		Config.GenChip = !Config.GenChip;
		break;

	  case GD_AsmGad04:
		Config.GenPin = !Config.GenPin;
		break;

	  case GD_AsmGad05:
		Config.AutoSave = !Config.AutoSave;
		break;

	  case GD_AsmGad06:
		Config.AutoGAL = !Config.AutoGAL;
		break;
	}
      }
    }
  }

  return(0);
}





/* FileSize:
   gibt die Länge einer Datei zurück
   Aufruf: size=FileSize(filename);
           filename: Zeiger auf Filenamen
   Ergebnis: -1 : File existiert nicht
	     -2 : kein Speicher für FileInfoBlock
	    size: Filelänge
*/
long FileSize(UBYTE *filename)
{
struct	FileInfoBlock	*fib;
struct	FileLock	*lock;
LONG	filesize;

 if((lock=(struct FileLock *) Lock((BYTE *)filename, (long)ACCESS_READ))) {
   fib=(struct FileInfoBlock *)AllocMem((long)sizeof(struct FileInfoBlock),MEMF_CHIP);
   if (fib!=NULL) {
     if (Examine((BPTR)lock, fib))
       filesize=fib->fib_Size;
     else filesize=-1L;
     UnLock((BPTR)lock);
     FreeMem(fib,(long)sizeof(struct FileInfoBlock));
     return(filesize);
    }
   else
     return(-2L);				/*Mem-Error*/
  }
 else
   return(-1L);					/*File existiert nicht*/
}



/* ReadFile
   File einlesen
   Aufruf: error=ReadFile(filename,filesize,filebuff)
           filename: Zeiger auf Filenamen
	   filesize: Größe der Datei in Bytes
	   filebuff: Adresse, an die die Datei gelesen werden soll
   Ergebnis: error: 1=kein Fehler, 0=Fehler
*/
int ReadFile(UBYTE *filename, LONG filesize, UBYTE *filebuff)
{
long 	actlength;
BPTR    fh;

 if ((fh=Open((char *)filename, (long)MODE_OLDFILE))) {
   actlength=Read(fh, (char *)filebuff, filesize);
   Close(fh);
   if (actlength==-1L) return(0);
   else return(1);
  }
 else
  return(0);
}




/*ErrorReq
  gibt zu einer Fehlernummer den entsprechenden Requester aus
  Aufruf: ErrorReq(errornum);
	  errornum: Fehlernummer
*/
void ErrorReq(int errornum)
{
 switch (errornum) {
   case  1:  MyRequest(ERR_REQ, AppStrings[MSG_ERR1].as_Str);
	     break;
   case  2:  MyRequest(ERR_REQ, AppStrings[MSG_ERR2].as_Str);
	     break;
   case  3:  MyRequest(ERR_REQ, AppStrings[MSG_ERR3].as_Str);
	     break;
   case  4:  MyRequest(ERR_REQ, AppStrings[MSG_ERR4].as_Str);
	     break;
   case  5:  MyRequest(ERR_REQ, AppStrings[MSG_ERR5].as_Str);
	     break;
   case  6:  MyRequest(ERR_REQ, AppStrings[MSG_ERR6].as_Str);
	     break;
   case  7:  MyRequest(ERR_REQ, AppStrings[MSG_ERR7].as_Str);
	     break;
   case  8:  MyRequest(ERR_REQ, AppStrings[MSG_ERR8].as_Str);
	     break;
   case  9:  MyRequest(ERR_REQ, AppStrings[MSG_ERR9].as_Str);
	     break;
   case 10:  MyRequest(ERR_REQ, AppStrings[MSG_ERR10].as_Str);
	     break;
   case 11:  MyRequest(ERR_REQ, AppStrings[MSG_ERR11].as_Str);
	     break;
   case 12:  MyRequest(ERR_REQ, AppStrings[MSG_ERR12].as_Str);
	     break;
   case 13:  MyRequest(ERR_REQ, AppStrings[MSG_ERR13].as_Str);
	     break;
  }
}




/* PrintText
   gibt Text im Text-Feld aus
   Aufruf: PrintText(text);
	   text   : Zeiger auf Text
	   newline: 1: ypos auf nächste Zeile
		    0: ypos nicht auf nächste Zeile
		       Aufruf mit newline = 0 eigentlich nur sinnvoll wenn
		       zuvor schon mal mit newline = 1 aufgerufen wurde
		       Anwendungsbeispiel:
			 PrintText("führe Verify durch...",1);
			 Nach erfolgreichem Verify: PrintText(" O.K.",0);
			 =>  "führe Verify durch... O.K."
*/
void PrintText(UBYTE *text, int newline)
{
static	long  delta_x;
static  int   ytxt = 150;			/*Startpos. für Text*/

  if (newline)
    if (ytxt < 180)
      ytxt += 10;
    else
      ScrollRaster(rp, 0L, 10L, 31L, 152L, 609L, 183L);

  if (newline)
    Move(rp, 40L, (long)ytxt);
  else
    Move(rp, 40L+delta_x, (long)ytxt);


  Text(rp, (char *)text, (long)strlen((char *)text));
  delta_x = (long)strlen((char *)text)*8L;

}



/*gibt "Fehler in Zeile xyz" aus
  Aufruf: PrintErrorLine(line);
	  line: Zeilennummer
*/
void PrintErrorLine(int line)
{

  sprintf((char *)&ErrorLineStr[16], "%4d:", line);

  PrintText(&ErrorLineStr[0],1);

}






/* Voreinstellungen laden ("s:GALer.config") und Menüs, Gadgets, usw.
   entsprechend einstellen
*/
void LoadConfig(void)
{
long 	filelength;
BPTR	fh;


 if ((fh = Open((char *)"s:GALer.config", (long)MODE_OLDFILE))) {
   filelength = Read(fh, (char *)&DummyConfig, (long)sizeof(struct Configuration));
   Close(fh);
   if (filelength == -1L)
     ErrorReq(10); 
   else					/* kein Fehler beim Lesen? */
     Config = DummyConfig;		/* dann Config übernehmen  */
  }

  GALType = UNKNOWN;

  SetGALType(Config.GALType);			/* set type of GAL */

  GALType = Config.GALType;


  ClearMenuStrip(window);			/* Menü ausschalten, um die */
						/* Flags ändern zu können   */

  if (Config.GALTypeReq)		 	/* Typ-Requester-Menü */
    ItemAddress(mainmenu, FULLMENUNUM(1, 5, NOSUB))->Flags |= CHECKED;


  hw_version = Config.HardwareVersion;		/* Hardware-Version */

  switch(Config.HardwareVersion) {

    case HW_GALER_1_0:
      ItemAddress(mainmenu, FULLMENUNUM(0, 1, 0))->Flags |= CHECKED;
      break;

    case HW_GALER_1_2:
      ItemAddress(mainmenu, FULLMENUNUM(0, 1, 1))->Flags |= CHECKED;
      break;

    case HW_GALER_1_3:
      ItemAddress(mainmenu, FULLMENUNUM(0, 1, 2))->Flags |= CHECKED;
      break;

  }


  ResetMenuStrip(window, mainmenu);		/* set menus */


  if (hw_version <= HW_GALER_1_2) {		/* enable/disable 22V10 */
    OffMenu(window, FULLMENUNUM(1, 2, 0));	/* and 20RA10 menu */
    OffMenu(window, FULLMENUNUM(1, 3, 0));

    if (GALType == GAL22V10 || GALType == GAL20RA10) /*set 16V8 if 22V10 or  */
      SetGALType(GAL16V8);			     /*20RA10 is selected and*/
						     /*and hardware is <= 1.2*/
  }
  else {
    OnMenu(window, FULLMENUNUM(1, 2, 0));
    OnMenu(window, FULLMENUNUM(1, 3, 0));
  }


  if (Config.GenJedec)
    AsmGTags[1] = TRUE;

  if (Config.GenFuse)
    AsmGTags[4] = TRUE;

  if (Config.GenChip)
    AsmGTags[7] = TRUE;

  if (Config.GenPin)
    AsmGTags[10] = TRUE;

  if (Config.AutoSave)
    AsmGTags[13] = TRUE;

  if (Config.AutoGAL)
    AsmGTags[16] = TRUE;



  if (Config.JedecSecBit)
    JEDGTags[1] = TRUE;

  if (Config.JedecFuseChk)
    JEDGTags[4] = TRUE;

  if (Config.JedecFileChk)
    JEDGTags[7] = TRUE;



  if (Config.ProgEmptyTest)
    WriteGTags[1] = TRUE;

  if (Config.ProgVerify)
    WriteGTags[4] = TRUE;

  if (Config.CopyEmptyTest)
    WriteGTags[7] = TRUE;

  if (Config.CopyVerify)
    WriteGTags[10] = TRUE;

  if (Config.EraseEmptyTest)
    WriteGTags[13] = TRUE;



  if (Config.EdWBToFront)		/* Workbench to front? */
    SelectEditorGTags[6] = TRUE;

					/* get string for editor call */
  SelectEditorGTags[1] = (ULONG)&Config.EditorStr[0];

}



/* Voreinstellungen sichern -  File "s:GALer.config"*/
void SaveConfig(void)
{
long 	filelength;
BPTR	fh;

  Config.GALType = GALType;
					/* get string for editor call */
  strcpy(&Config.EditorStr[0], (char *)((struct StringInfo *)
			SelectEditorGadgets[0]->SpecialInfo)->Buffer);

  if ((fh = Open((char *)"s:GALer.config", (long)MODE_NEWFILE))) {
    filelength = Write(fh, (char *)&Config, (long)sizeof(struct Configuration));

    Close(fh);

    if (filelength == -1L)
      ErrorReq(11);
  }
  else
    ErrorReq(11);

}




/* SetGALType: alle Variablen usw. auf den gewünschten GAL-Typ einstellen
   Aufruf:     SetGALType(galtype);
   Parameter:  galtype = GAL16V8, GAL20V8, GAL22V10, GAL20RA10
*/
void SetGALType(int galtype)
{

  ClearMenuStrip(window);			/* Menüs auschalten, um die */
						/* Flags ändern zu können   */

  if ((galtype == GAL16V8) && (GALType != GAL16V8)) {
    GALType    = GAL16V8;
    MaxFuseAdr = MAX_FUSE_ADR16;
    RowSize    = ROW_SIZE_16V8;
    XORSize    = 8;
    SigAdr     = SIG_ADR16;

    SetGAL  (GAL16V8);
    DrawGAL (GAL16V8);

    strncpy ((char *)&title[59], (char *)"GAL16V8  ", (size_t)9);

					/* 16V8-Menü Amiga-Haken setzen*/
    ItemAddress(mainmenu, FULLMENUNUM(1, 0, NOSUB))->Flags |= CHECKED;

					/* 20V8, 22V10, 22RA10-Menü */
    ItemAddress(mainmenu, FULLMENUNUM(1, 1, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 2, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 3, NOSUB))->Flags &= ~CHECKED;
  }


  if ((galtype == GAL20V8) && (GALType != GAL20V8)) {
    GALType    = GAL20V8;
    MaxFuseAdr = MAX_FUSE_ADR20;
    RowSize    = ROW_SIZE_20V8;
    XORSize    = 8;
    SigAdr     = SIG_ADR20;

    SetGAL  (GAL20V8);
    DrawGAL (GAL20V8);

    strncpy ((char *)&title[59], (char *)"GAL20V8  ", (size_t)9);

					/* 20V8-Menü Amiga-Haken setzen*/
    ItemAddress(mainmenu, FULLMENUNUM(1, 1, NOSUB))->Flags |= CHECKED;

					/* 16V8, 22V10, 22RA10-Menü */
    ItemAddress(mainmenu, FULLMENUNUM(1, 0, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 2, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 3, NOSUB))->Flags &= ~CHECKED;
  }


  if ((galtype == GAL22V10) && (GALType != GAL22V10)) {
    GALType    = GAL22V10;
    MaxFuseAdr = MAX_FUSE_ADR22V10;
    RowSize    = ROW_SIZE_22V10;
    XORSize    = 10;
    SigAdr     = SIG_ADR22V10;

    SetGAL  (GAL22V10);
    DrawGAL (GAL22V10);

    strncpy ((char *)&title[59], (char *)"GAL22V10 ", (size_t)9);

					/* 22V10-Menü Amiga-Haken setzen*/
    ItemAddress(mainmenu, FULLMENUNUM(1, 2, NOSUB))->Flags |= CHECKED;

					/* 16V8, 20V8, 22RA10-Menü */
    ItemAddress(mainmenu, FULLMENUNUM(1, 0, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 1, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 3, NOSUB))->Flags &= ~CHECKED;
  }


  if ((galtype == GAL20RA10) && (GALType != GAL20RA10)) {
    GALType    = GAL20RA10;
    MaxFuseAdr = MAX_FUSE_ADR20RA10;
    RowSize    = ROW_SIZE_20RA10;
    XORSize    = 10;
    SigAdr     = SIG_ADR20RA10;

    SetGAL  (GAL20RA10);
    DrawGAL (GAL20RA10);

    strncpy ((char *)&title[59], (char *)"GAL20RA10", (size_t)9);

					/* 22V10-Menü Amiga-Haken setzen*/
    ItemAddress(mainmenu, FULLMENUNUM(1, 3, NOSUB))->Flags |= CHECKED;

					/* 16V8, 20V8, 22RA10-Menü */
    ItemAddress(mainmenu, FULLMENUNUM(1, 0, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 1, NOSUB))->Flags &= ~CHECKED;
    ItemAddress(mainmenu, FULLMENUNUM(1, 2, NOSUB))->Flags &= ~CHECKED;
  }



  SetWindowTitles(window, (char *)-1L, (char *)title);


  ResetMenuStrip(window, mainmenu);		/* Menüs wieder setzen */

}






/* Die Routienen  "AddByte", "AddString", "IncPointer", "DecPointer" und
   "FreeBuffer" erleichtern die Erstellung und Bearbeitung von verketteten
   Speicherlisten.
*/


/*AddByte:   Schreibt das Byte "code" in den Puffer. Wenn das Ende des
	     Puffers erreicht ist, wird ein neuer erstellt
	     (Struktur Buffer).
  Aufruf   : result = AddByte(buff,code);
  Einsprung: code: Byte das in den Puffer an die Position "buff"
	     geschrieben werden soll, "buff" wird anschließend um eins erhöht
	     buff: Zeiger auf ActBuffer-Struktur
  Ergebnis:  Returnwert = 0: alles o.k.    sonst: Fehler (kein Speicher)
	     buff enthält neuen Entry-Zeiger und den entsprechenden Puffer-
	     Anfang und das Ende
*/
int AddByte(struct ActBuffer *buff, UBYTE code)
{
struct	Buffer	*mybuff;

 if ((buff->Entry) < (buff->BuffEnd)) {		/*noch im Puffer?*/
   *buff->Entry++ = code;			/*ja, dann Byte eintragen*/
  }
 else {					/*nein, dann neuen Puffer erstellen*/
   if (!(mybuff = (struct Buffer *)AllocMem((long)sizeof(struct Buffer),MEMF_PUBLIC|MEMF_CLEAR))) {
     ErrorReq(2);			/*kein Speicher mehr->Fehlermeldung*/
     return(-1);
    }
   buff->ThisBuff->Next   = mybuff;	/*neuer Puffer ist aktueller*/
   mybuff->Prev   = buff->ThisBuff;	/*vorheriger Puffer ist alter*/
   buff->ThisBuff = mybuff;		/*aktueller Puffer ist neuer*/
   buff->Entry    = (UBYTE *)(&mybuff->Entries[0]);
   buff->BuffEnd  = (UBYTE *)mybuff + (long)sizeof(struct Buffer);
   *buff->Entry++ = code;
  }
 return(0);
}



/*AddString: Schreibt den String "strnptr" in den Puffer. Wenn das Ende des
	     Puffers erreicht ist, wird ein neuer erstellt.
	     (Struktur Buffer).
  Aufruf   : result = AddString(buff,strnptr);
  Einsprung: strnptr: Zeiger auf String der in den Puffer an die Position
	     "buff" geschrieben werden soll, "buff" zeigt zum Schluß auf
	     das lezte Zeichen im String + 1.
	     buff: Zeiger auf ActBuffer-Struktur
  Ergebnis:  Returnwert = 0: alles o.k.    sonst: Fehler (kein Speicher)
	     buff enthält neuen Entry-Zeiger und den entsprechenden Puffer-
	     Anfang und das Ende
*/
int AddString(struct ActBuffer *buff, UBYTE *strnptr)
{
  while (*strnptr) {
    if (AddByte(buff,*strnptr++))
      return(-1);
  }
  return(0);
}



/*IncPointer:   Zeiger  auf nächsten Eintrag im verketten Puffer

   Aufruf:     IncPointer(buff);
   Parameter:	buff  	      : Zeiger auf ActBuffer-Struktur
   Ergebnis :	buff->Entry   : zeigt auf nächstes Zeichen im Puffer
		buff->BuffEnd : zeigt auf das Ende des Puffers, in den
			        Entry zeigt
		buff->ThisBuff: zeigt auf Puffer-Anfang
ACHTUNG: es erfolgt keine Abfrage, ob das Ende des gesamten Puffers
	 schon erreicht ist
*/
void IncPointer(struct ActBuffer *buff)
{

  buff->Entry++;

  if (buff->Entry == buff->BuffEnd) {	/*Pufferende erreicht?*/
    buff->ThisBuff = buff->ThisBuff->Next; /*ja, dann auf nächsten Puffer*/

    buff->Entry    = (UBYTE *)(&buff->ThisBuff->Entries[0]);

    buff->BuffEnd  = (UBYTE *)buff->ThisBuff + (long)sizeof(struct Buffer);
  }

}


/*DecPointer:   Zeiger  auf vorigen Eintrag im verketten Puffer

   Aufruf:      IncPointer(buff);
   Parameter:	buff  	      : Zeiger auf ActBuffer-Struktur
   Ergebnis :	buff->Entry   : zeigt auf voriges Zeichen im Puffer
		buff->BuffEnd : zeigt auf das Ende des Puffers, in den
			        Entry zeigt
		buff->ThisBuff : zeigt auf Puffer-Anfang
ACHTUNG: es erfolgt keine Abfrage, ob der Anfang des gesamten Puffers
	 schon erreicht ist
*/
void DecPointer(struct ActBuffer *buff)
{

  buff->Entry--;

  if (buff->Entry < &buff->ThisBuff->Entries[0]) { /*Pufferanfang erreicht?*/
    buff->ThisBuff = buff->ThisBuff->Prev;	/*dann auf vorigen Puffer*/

    buff->BuffEnd  = (UBYTE *)buff->ThisBuff + (long)sizeof(struct Buffer);

    buff->Entry    = (UBYTE *)((buff->BuffEnd)-1L);
  }

}


/*FreeBuffer:   gibt die verketteten Puffer wieder frei
 Aufruf:      FreeBuffer(buff);
 Einsprung:   buff: Zeiger auf ersten Speicherblock
 Ergebnis :   ---
*/
void FreeBuffer(struct Buffer *buff)
{
struct	Buffer	*nextbuff;

  do {

    nextbuff = buff->Next;

    FreeMem(buff,(long)sizeof(struct Buffer)); }

  while (buff = nextbuff);
}




/* open window to select editor
*/
void SelectEditor(void)
{
struct	Window 	        *SelEdWin;
struct	IntuiMessage	*imsg;
ULONG	class;
USHORT	code, gadID;
UWORD	offy = screen->WBorTop + screen->RastPort.TxHeight + 1;


  if (!(SelEdWin = OpenWindowTags( NULL,
				WA_Left,	165,
				WA_Top,		25,
				WA_Width,	310,
				WA_Height,	78 + offy,
				WA_IDCMP,	STRINGIDCMP|CHECKBOXIDCMP|BUTTONIDCMP|IDCMP_GADGETDOWN|IDCMP_VANILLAKEY|
						IDCMP_REFRESHWINDOW,
				WA_Flags,	WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
				WA_Gadgets,	SelectEditorGList,
				WA_Title,	AppStrings[MSG_SELEDITOR_WIN].as_Str,
				WA_CustomScreen, screen,
				TAG_DONE )))
    return;


  GT_RefreshWindow(SelEdWin, NULL);


  for (;;) {

    Wait (1 << SelEdWin->UserPort->mp_SigBit);

    while (imsg = GT_GetIMsg(SelEdWin->UserPort)) {

      class = imsg->Class;
      code  = imsg->Code;

      if (class == GADGETUP)
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

      GT_ReplyIMsg(imsg);


      if (class == VANILLAKEY) {
	if (code == 13) {			/* Return-Key = Weiter */
	  CloseWindow(SelEdWin);
	  return;
	}
      }

      if (class == GADGETUP) {
        gadID = ((struct Gadget *)imsg->IAddress)->GadgetID;

	switch (gadID) {

	  case GD_SelEdGad02:
	    Config.EdWBToFront = !Config.EdWBToFront;
	    break;

	  case GD_SelEdGad03:
	    CloseWindow(SelEdWin);
	    return;
	    break;

	}
      }
    }
  }
}



/* call editor and replace %s with current *.pld
*/
void CallEditor(void)
{
char  callstrn[100 + EDITOR_STR_SIZE];
BPTR  ofh;


  if (Config.EdWBToFront)			/* bring WB to front? */
    WBenchToFront();


  if (ofh = Open("NIL:", (long)MODE_NEWFILE)) {	/* open file handle */

    if (strlen(prevSourceFile) <= 100) {	/* is string too long? */

      sprintf(&callstrn[0], (char *)((struct StringInfo *)
		    	    SelectEditorGadgets[0]->SpecialInfo)->Buffer,
			    prevSourceFile);

      if (Execute(&callstrn[0], NULL, ofh) == FALSE)
        rtEZRequestTags(AppStrings[MSG_CALLED_ERR].as_Str,
		     AppStrings[MSG_CANCEL_GAD].as_Str, NULL, NULL, RT_ReqPos,
		     REQPOS_CENTERSCR, TAG_END);

    }

    Close(ofh);					/* close output file handle */

  }

  if (Config.EdWBToFront) {
    ScreenToFront(screen);		/* get back GALer's window */

    ActivateWindow(window);
  }
}

