#define STRINGARRAY

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <libraries/locale.h>
#include <libraries/asl.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <graphics/displayinfo.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/asl.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/diskfont.h>
#include <proto/keymap.h>
#include <proto/locale.h>
#include <proto/icon.h>
#include <proto/wb.h>
#include <stdlib.h>
#include <string.h>

#include "filezap.h"

#define GD_First		0
#define GD_FName		0
#define GD_SearchStr	1
#define GD_Scroller		2
#define GD_Start		3
#define GD_End			4
#define GD_Save			5
#define GD_Undo			6
#define GD_SSearch		7
#define GD_Quit			8
#define GD_SearchBack	9
#define GD_CaseSense	10
#define GD_Goto			11
#define GD_Mode			12
#define GD_FSize		13
#define GD_Last			13

#define HEX 1
#define ASC 2
#define ON TRUE
#define OFF FALSE

extern void tsprintf(char *,char *,...);

static STRPTR GetLangStr(LONG id);
static int InitStuff(void);
static void CleanStuff(void);
static char __asm hexchar(register __d0 char h);
static void DisplayLine(UBYTE *buffer,int bsize,int lnum);
static void Resume(char *title,char *strmsg,BOOL gd);
static __saveds void About(void);
static __saveds void Help(void);
static void SetDispMode(void);
static void DoOpenFile(void);
static void ReadBuff(void);
static void DoTheSearch(void);
static void CheckChange(void);
static void DispBuff(BOOL us);
static void Cursor(BOOL state);
static void SaveFile(void);
static void RestoreBuffer(void);
static void SetScroller(long top);
static void DoScroller(ULONG lnum);
static void Beep(void);
static void MoveLeft(void);
static void MoveRight(void);
static void MoveUp(void);
static void MoveDown(void);
static BOOL CompMem(register UBYTE *block1,register UBYTE *block2,register int size);
static BOOL check_key(void);
static void InsertBytes(int size);
static void DeleteBytes(int size);
static void DispSize(void);
static void MoveStart(void);
static void MoveEnd(void);
void main(int argc,char *argv[]);

static USHORT chip WaitSpriteData[] = {
	0x0000,0x0000,0x0000,0x0FE0,0x0740,0x18B0,0x0FE0,0x7018,
	0x3FF0,0xC008,0x7FF0,0x9E0C,0x7FF8,0x8406,0x7FFC,0x8802,
	0xFFFC,0x1E03,0x7FFE,0x80F1,0x7FFE,0x8021,0x3FFF,0x4040,
	0x7FFE,0x80F1,0x3FFE,0xC001,0x1FFC,0x6003,0x0FF8,0x3006,
	0x03F0,0x1C0C,0x00E0,0x0718,0x0780,0x0870,0x0FE0,0x1010,
	0x0740,0x0820,0x0000,0x0FE0,0x01C0,0x0220,0x03E0,0x0410,
	0x00C0,0x0330,0x0000,0x00E0,0x0000,0x0000
};
static UBYTE trans_table[256] = {
	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
	0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,
	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
	0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
	0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
	0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
	0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xD7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xDF,
	0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
	0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
};

char hex_str[] = "0123456789ABCDEF";

struct GfxBase *GfxBase;
struct Library *AslBase;
struct Library *KeymapBase;
struct Library *LocaleBase;
struct Library *GadToolsBase;
struct Library *WorkbenchBase;
struct Library *DiskfontBase = NULL;
struct IntuitionBase *IntuitionBase;
struct TextFont *topazfnt = NULL;
static struct Window *Wnd = NULL;
static struct Screen *Scr = NULL;
static APTR VisualInfo = NULL;
static struct Gadget *GList = NULL;
static struct Gadget *Gadgets[GD_Last+1];
static struct Menu *Menus = NULL;
static struct FileRequester *FReq = NULL;
static struct MsgPort *AppMPort;
static struct AppWindow *AWnd;
static struct AppMessage *AMsg;
static struct Locale *loc;
static struct Catalog *ctlg;
static UWORD Zoom[4] = {0,13,200,14};
static UWORD TopBarSize;
static UWORD LeftBarSize;
static struct TextAttr topaz11 = {(STRPTR)"topaz.font",11,0x00,0x01};
static ULONG coffs = 0;
static BPTR fptr = NULL;
static UBYTE fname[80];
static LONG cx,hcx,cy,mode,slen;
static ULONG fsize,num_lines,num_shf;
static char mode_str[4];
static char fs_str[20];
static char gstr[12];
static char sstr[128];
static char tstr[128];
static BYTE rbuff[256];
static BYTE ubuff[256];
static BOOL searching;
static BOOL search_forward;
static BOOL scase_dep;
static BOOL shift,ctrl;
static int soffs,lsize,dtype,rb_size;
static int run_pros,goto_offs;
static struct TagItem WindowTags[] = {
	WA_Left,		0,
	WA_Top,			13,
	WA_InnerWidth,	625,
	WA_InnerHeight,	232,
	WA_IDCMP,		IDCMP_REFRESHWINDOW|IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE|
					IDCMP_GADGETDOWN|IDCMP_GADGETUP|IDCMP_MENUPICK|
					IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_INTUITICKS|
					IDCMP_REFRESHWINDOW|IDCMP_MOUSEBUTTONS,
	WA_Flags,		WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|
					WFLG_SMART_REFRESH|WFLG_ACTIVATE|WFLG_NEWLOOKMENUS,
	WA_Gadgets,		0l,
	WA_Title,		(Tag)"FileZAP 2.1",
	WA_ScreenTitle,	(Tag)"FileZAP 2.1 by Torstein Pettersen",
	WA_MinWidth,	67,
	WA_MinHeight,	21,
	WA_MaxWidth,	640,
	WA_MaxHeight,	512,
	WA_Zoom,		(Tag)Zoom,
	TAG_DONE
};
static struct TagItem BevelTags[] = {
	GT_VisualInfo,	NULL,
	TAG_DONE
};
static struct TagItem BevelTags2[] = {
	GT_VisualInfo,	NULL,
	GTBB_Recessed,	TRUE,
	TAG_DONE
};
static struct TagItem ScrollTags[] = {
	GTSC_Arrows,	8,
	PGA_Freedom,	LORIENT_VERT,
	GA_Immediate,	TRUE,
	GA_RelVerify,	TRUE,
	TAG_DONE
};
static struct TagItem ScrollTags2[] = {
	GTSC_Top,		0,
	GTSC_Total,		0,
	GTSC_Visible,	0,
	TAG_DONE
};
static struct TagItem StrTags[] = {
	GTST_MaxChars,	128,
	TAG_DONE
};
static struct TagItem GotoTags[] = {
	GTST_MaxChars,	10,
	TAG_DONE
};
static struct TagItem CSenseTags[] = {
	GTCB_Checked,	TRUE,
	TAG_DONE
};
static struct TagItem FNameTags[] = {
	GTST_String,	(ULONG)fname,
	TAG_DONE
};
static struct TagItem NullTags[] = {
	TAG_DONE
};
static struct TagItem DisableTags[] = {
	GA_Disabled,	TRUE,
	TAG_DONE
};
static struct TagItem EnableTags[] = {
	GA_Disabled,	FALSE,
	TAG_DONE
};
static struct TagItem ModeStrTags[] = {
	GTTX_Text,		(ULONG)mode_str,
	GTTX_Border,	TRUE,
	TAG_DONE
};
static struct TagItem FSStrTags[] = {
	GTTX_Text,		(ULONG)fs_str,
	GTTX_Border,	TRUE,
	TAG_DONE
};
static struct TagItem AboutTags[] = {
	NP_Entry,		(ULONG)&About,
	NP_Name,		(ULONG)"FileZAP About",
	TAG_DONE
};
static struct TagItem HelpTags[] = {
	NP_Entry,		(ULONG)&Help,
	NP_Name,		(ULONG)"FileZAP Help",
	TAG_DONE
};
static struct TagItem MenuTags[] = {
	GTMN_FrontPen,	1,
	TAG_DONE
};
#define MENU_TITLES 28
static struct {
	LONG id;
	LONG id_c;
} menu_names[] = {
	{MSG_MENU_PROJECT,0},
	{MSG_MENU_PROJECT_OPEN,MSG_MENU_PROJECT_OPEN_C},
	{MSG_MENU_PROJECT_SAVE,MSG_MENU_PROJECT_SAVE_C},
	{MSG_MENU_PROJECT_GOTO,MSG_MENU_PROJECT_GOTO_C},
	{0,0},
	{MSG_MENU_PROJECT_NSHELL,MSG_MENU_PROJECT_NSHELL_C},
	{MSG_MENU_PROJECT_HELP,MSG_MENU_PROJECT_HELP_C},
	{MSG_MENU_PROJECT_ABOUT,MSG_MENU_PROJECT_ABOUT_C},
	{MSG_MENU_PROJECT_QUIT,MSG_MENU_PROJECT_QUIT_C},
	{MSG_MENU_EDIT,0},
	{MSG_MENU_EDIT_UNDO,MSG_MENU_EDIT_UNDO_C},
	{MSG_MENU_EDIT_INSERT,0},
	{MSG_MENU_EDIT_INSERT_1BYTE,MSG_MENU_EDIT_INSERT_1BYTE_C},
	{MSG_MENU_EDIT_INSERT_1WORD,MSG_MENU_EDIT_INSERT_1WORD_C},
	{MSG_MENU_EDIT_INSERT_1LONG,MSG_MENU_EDIT_INSERT_1LONG_C},
	{MSG_MENU_EDIT_INSERT_4LONG,MSG_MENU_EDIT_INSERT_4LONG_C},
	{MSG_MENU_EDIT_DELETE,0},
	{MSG_MENU_EDIT_DELETE_1BYTE,MSG_MENU_EDIT_DELETE_1BYTE_C},
	{MSG_MENU_EDIT_DELETE_1WORD,MSG_MENU_EDIT_DELETE_1WORD_C},
	{MSG_MENU_EDIT_DELETE_1LONG,MSG_MENU_EDIT_DELETE_1LONG_C},
	{MSG_MENU_EDIT_DELETE_4LONG,MSG_MENU_EDIT_DELETE_4LONG_C},
	{MSG_MENU_EDIT_DISPLAY,0},
	{MSG_MENU_EDIT_DISPLAY_BYTE,MSG_MENU_EDIT_DISPLAY_BYTE_C},
	{MSG_MENU_EDIT_DISPLAY_WORD,MSG_MENU_EDIT_DISPLAY_WORD_C},
	{MSG_MENU_EDIT_DISPLAY_LONG,MSG_MENU_EDIT_DISPLAY_LONG_C},
	{MSG_MENU_SEARCH,0},
	{MSG_MENU_SEARCH_SEARCH_FOR,MSG_MENU_SEARCH_SEARCH_FOR_C},
	{MSG_MENU_CONTINUE_SEARCH,MSG_MENU_CONTINUE_SEARCH_C},
	{0,0}
};
static struct NewMenu NewMenu[] = {
	NM_TITLE,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_ITEM,NM_BARLABEL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_TITLE,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL, NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_SUB,NULL,NULL,CHECKIT|MENUTOGGLE|CHECKED,~1,NULL,
	NM_SUB,NULL,NULL,CHECKIT|MENUTOGGLE,~2,NULL,
	NM_SUB,NULL,NULL,CHECKIT|MENUTOGGLE,~4,NULL,
	NM_TITLE,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_ITEM,NULL,NULL,0,0,NULL,
	NM_END,NULL,NULL,0,0,NULL
};

static STRPTR GetLangStr(LONG id)
{
	if (LocaleBase != NULL)
		return(GetCatalogStr(ctlg,id,AppStrings[id-1].as_Str));
	else
		return(AppStrings[id-1].as_Str);
}

static int InitStuff(void)
{
	struct NewGadget ng;
	struct Gadget *g;
	int l;

	Menus = NULL;
	FReq = NULL;
	Wnd = NULL;
	GList = NULL;
	VisualInfo = NULL;
	Scr = NULL;
	GadToolsBase = NULL;
	AslBase = NULL;
	GfxBase = NULL;
	KeymapBase = NULL;
	LocaleBase = NULL;
	WorkbenchBase = NULL;
	IntuitionBase = NULL;
	AWnd = NULL;
	loc = NULL;
	ctlg = NULL;
	AppMPort = NULL;
	searching = FALSE;
	search_forward = TRUE;
	scase_dep = FALSE;
	shift = ctrl = FALSE;
	fptr = NULL;
	run_pros = 0;
	fsize = slen = dtype = rb_size = 0;
	cx = cy = 0;
	mode = HEX;
	SetDispMode();
	strcpy(fs_str,"                   ");

	if (!(IntuitionBase = OpenLibrary("intuition.library",37)) ||
		!(WorkbenchBase = OpenLibrary("workbench.library",37)) ||
		!(GfxBase = OpenLibrary("graphics.library",37)) ||
		!(AslBase = OpenLibrary("asl.library",37)) ||
		!(GadToolsBase = OpenLibrary("gadtools.library",37)) ||
		!(DiskfontBase = OpenLibrary("diskfont.library",0)) ||
		!(KeymapBase = OpenLibrary("keymap.library",37)) ||
		!(AppMPort = CreateMsgPort()) ||
		!(FReq = AllocFileRequest()))
		return(1);

	if (LocaleBase = OpenLibrary("locale.library",37)) {
		loc = OpenLocale(NULL);
		ctlg = OpenCatalog(loc,"filezap.catalog",OC_BuiltInLanguage,(Tag)"norsk",OC_BuiltInCodeSet,0,TAG_DONE);
	}

	if (!(Scr = LockPubScreen("Workbench")))
		return(1);

	if (!(VisualInfo = GetVisualInfoA(Scr,NullTags)))
		return(2);

	if (!(g = CreateContext(&GList)))
		return(3);

	for (l = 0; l < MENU_TITLES; l++) {
		if (menu_names[l].id != 0)
			NewMenu[l].nm_Label = GetLangStr(menu_names[l].id);

		if (menu_names[l].id_c != 0)
			NewMenu[l].nm_CommKey = GetLangStr(menu_names[l].id_c);
	}

	Zoom[1] = Zoom[3] = TopBarSize = (UWORD)Scr->WBorTop + Scr->Font->ta_YSize + 1;
	LeftBarSize = (UWORD)Scr->WBorLeft;
	WindowTags[1].ti_Data = (ULONG)Zoom[3];

	if (Scr->Height > 399) {
		WindowTags[3].ti_Data = 232;
		topaz11.ta_YSize = 11;
		lsize = 11;
		soffs = 0;
		topazfnt = OpenDiskFont(&topaz11);
	}
	else {
		WindowTags[3].ti_Data = 179;
		topaz11.ta_YSize = 8;
		lsize = 8;
		soffs = -48;
	}

	ng.ng_LeftEdge = LeftBarSize + 83;
	ng.ng_TopEdge = TopBarSize + 1;
	ng.ng_Width = 219;
	ng.ng_Height = lsize + 4;
	ng.ng_GadgetText = GetLangStr(MSG_FILE_NAME_TITLE);
	ng.ng_TextAttr = &topaz11;
	ng.ng_GadgetID = GD_FName;
	ng.ng_Flags = PLACETEXT_LEFT | NG_HIGHLABEL;
	ng.ng_VisualInfo = VisualInfo;
	Gadgets[GD_FName] = g = CreateGadgetA(STRING_KIND,g,&ng,StrTags);

	ng.ng_LeftEdge = LeftBarSize + 403;
	ng.ng_GadgetText = GetLangStr(MSG_SEARCH_FOR);
	ng.ng_GadgetID = GD_SearchStr;
	Gadgets[GD_SearchStr] = g = CreateGadgetA(STRING_KIND,g,&ng,StrTags);

	ng.ng_LeftEdge = LeftBarSize + 606;
	ng.ng_TopEdge = TopBarSize + 17;
	ng.ng_Width = 16;
	ng.ng_Height = 181 + soffs;
	ng.ng_GadgetText = 0l;
	ng.ng_GadgetID = GD_Scroller;
	ng.ng_Flags = 0;
	Gadgets[GD_Scroller] = g = CreateGadgetA(SCROLLER_KIND,g,&ng,ScrollTags);

	ng.ng_LeftEdge = LeftBarSize + 66;
	ng.ng_TopEdge = TopBarSize + soffs + 200 - (lsize == 8 ? 1 : 0);
	ng.ng_Width = 61;
	ng.ng_Height = lsize + 3;
	ng.ng_GadgetText = GetLangStr(MSG_START_BUTTON);
	ng.ng_GadgetID = GD_Start;
	ng.ng_Flags = PLACETEXT_IN;
	Gadgets[GD_Start] = g = CreateGadgetA(BUTTON_KIND,g,&ng,NullTags);

	ng.ng_TopEdge = TopBarSize + soffs + 216 - (lsize == 8 ? 3 : 0);
	ng.ng_GadgetText = GetLangStr(MSG_END_BUTTON);
	ng.ng_GadgetID = GD_End;
	Gadgets[GD_End] = g = CreateGadgetA(BUTTON_KIND,g,&ng,NullTags);

	ng.ng_LeftEdge = LeftBarSize + 2;
	ng.ng_TopEdge = TopBarSize + soffs + 200 - (lsize == 8 ? 1 : 0);
	ng.ng_GadgetText = GetLangStr(MSG_SAVE_BUTTON);
	ng.ng_GadgetID = GD_Save;
	Gadgets[GD_Save] = g = CreateGadgetA(BUTTON_KIND,g,&ng,NullTags);

	ng.ng_TopEdge = TopBarSize + soffs + 216 - (lsize == 8 ? 3 : 0);
	ng.ng_GadgetText = GetLangStr(MSG_UNDO_BUTTON);
	ng.ng_GadgetID = GD_Undo;
	Gadgets[GD_Undo] = g = CreateGadgetA(BUTTON_KIND,g,&ng,NullTags);

	ng.ng_LeftEdge = LeftBarSize + 130;
	ng.ng_TopEdge = TopBarSize + soffs + 200 - (lsize == 8 ? 1 : 0);
	ng.ng_GadgetText = GetLangStr(MSG_SEARCH_BUTTON);
	ng.ng_GadgetID = GD_SSearch;
	Gadgets[GD_SSearch] = g = CreateGadgetA(BUTTON_KIND,g,&ng,NullTags);

	ng.ng_TopEdge = TopBarSize + soffs + 216 - (lsize == 8 ? 3 : 0);
	ng.ng_GadgetText = GetLangStr(MSG_QUIT_BUTTON);
	ng.ng_GadgetID = GD_Quit;
	Gadgets[GD_Quit] = g = CreateGadgetA(BUTTON_KIND,g,&ng,NullTags);

	ng.ng_LeftEdge = LeftBarSize + 200;
	ng.ng_TopEdge = TopBarSize + soffs + 199;
	ng.ng_GadgetText = GetLangStr(MSG_SEARCH_BACK_TXT);
	ng.ng_GadgetID = GD_SearchBack;
	ng.ng_Flags = PLACETEXT_RIGHT | NG_HIGHLABEL;
	Gadgets[GD_SearchBack] = g = CreateGadgetA(CHECKBOX_KIND,g,&ng,NullTags);

	ng.ng_TopEdge = TopBarSize + soffs + 215 - (lsize == 8 ? 2 : 0);
	ng.ng_GadgetText = GetLangStr(MSG_CASE_TXT);
	ng.ng_GadgetID = GD_CaseSense;
	Gadgets[GD_CaseSense] = g = CreateGadgetA(CHECKBOX_KIND,g,&ng,NullTags);

	ng.ng_LeftEdge = LeftBarSize + 534;
	ng.ng_TopEdge = TopBarSize + soffs + 199;
	ng.ng_Width = 88;
	ng.ng_Height = lsize + 4;
	ng.ng_GadgetText = GetLangStr(MSG_GOTO_TXT);
	ng.ng_GadgetID = GD_Goto;
	ng.ng_Flags = PLACETEXT_LEFT | NG_HIGHLABEL;
	Gadgets[GD_Goto] = g = CreateGadgetA(STRING_KIND,g,&ng,GotoTags);

	ng.ng_LeftEdge = LeftBarSize + 430;
	ng.ng_Width = 32;
	ng.ng_GadgetText = GetLangStr(MSG_MODE_TXT);
	ng.ng_GadgetID = GD_Mode;
	Gadgets[GD_Mode] = g = CreateGadgetA(TEXT_KIND,g,&ng,ModeStrTags);

	ng.ng_LeftEdge = LeftBarSize + 462;
	ng.ng_TopEdge = TopBarSize + soffs + 215 - (lsize == 8 ? 2 : 0);
	ng.ng_Width = 160;
	ng.ng_GadgetText = GetLangStr(MSG_FILESIZE);
	ng.ng_GadgetID = GD_FSize;
	Gadgets[GD_FSize] = g = CreateGadgetA(TEXT_KIND,g,&ng,FSStrTags);

	if (!g)
		return(4);

	WindowTags[6].ti_Data = (Tag)GList;

	if (!(Menus = CreateMenusA(NewMenu,NullTags)))
		return(6);

	LayoutMenusA(Menus,VisualInfo,MenuTags);

	if (!(Wnd = OpenWindowTagList(0l,WindowTags)))
		return(5);

	if (!(AWnd = AddAppWindow(1,0,Wnd,AppMPort,NULL)))
		return(7);

	SetMenuStrip(Wnd,Menus);
	GT_RefreshWindow(Wnd,0l);
	BevelTags[0].ti_Data = BevelTags2[0].ti_Data = (Tag)VisualInfo;
	GT_SetGadgetAttrsA(Gadgets[GD_CaseSense],Wnd,NULL,CSenseTags);
	DrawBevelBoxA(Wnd->RPort,LeftBarSize+2,TopBarSize+17,602,181+soffs,BevelTags);
	DrawBevelBoxA(Wnd->RPort,LeftBarSize+4,TopBarSize+18,598,179+soffs,BevelTags2);
	coffs = 0;
	return(0);
}

static void CleanStuff(void)
{
	if (run_pros > 0)
		Resume(GetLangStr(MSG_PANIC_1),GetLangStr(MSG_PANIC_2),TRUE);

	while (run_pros > 0);

	if (AWnd)
		RemoveAppWindow(AWnd);

	if (AppMPort) {
		while (AMsg = (struct AppMessage *)GetMsg(AppMPort))
            ReplyMsg((struct Message *)AMsg);

		DeleteMsgPort(AppMPort);
	}

	if (fptr)
		Close(fptr);

	if (Menus) {
		ClearMenuStrip(Wnd);
		FreeMenus(Menus);
	}

	if (FReq)
		FreeFileRequest(FReq);

	if (Wnd)
		CloseWindow(Wnd);

	if (GList)
		FreeGadgets(GList);

	if (VisualInfo)
		FreeVisualInfo(VisualInfo);

	if (Scr)
		UnlockPubScreen(0l,Scr);

	if (topazfnt) 
		CloseFont(topazfnt);

	if (ctlg)
		CloseCatalog(ctlg);

	if (loc)
		CloseLocale(loc);

	if (LocaleBase)
		CloseLibrary(LocaleBase);

	if (KeymapBase)
		CloseLibrary(KeymapBase);

	if (DiskfontBase)
		CloseLibrary(DiskfontBase);

	if (GadToolsBase)
		CloseLibrary(GadToolsBase);

	if (AslBase)
		CloseLibrary(AslBase);

	if (GfxBase)
		CloseLibrary(GfxBase);

	if (WorkbenchBase)
		CloseLibrary(WorkbenchBase);

	if (IntuitionBase)
		CloseLibrary(IntuitionBase);
}

static char __asm hexchar(register __d0 char h)
{
	h &= 0x0F;

	if (h > 9)
		h += 7;

	return((char)(h + '0'));
}

static void DisplayLine(UBYTE *buffer,int bsize,int lnum)
{
	UBYTE *p,*op,*op2;
	static UBYTE ob[80];
	static struct IntuiText ot = {1,0,JAM2,0,0,&topaz11,ob,NULL};
	ULONG tval;
	int i;

	memset(ob,' ',80);

	if (bsize > 0) {
		tval = coffs + (lnum << 4);

		for (i = 7; i >= 0; i--) {
			ob[i] = hexchar((char)tval);
			tval >>= 4;
		}

		ob[8] = ':';
		op = &ob[10];

		switch (dtype) {
			case 0:
				op2 = &ob[58];
				break;
			case 1:
				op2 = &ob[50];
				break;
			case 2:
				op2 = &ob[46];
				break;
		}

		for (i = 0,p = buffer; i < bsize; i++) {
			*op++ = hexchar(*p >> 4);
			*op++ = hexchar(*p);

			switch (dtype) {
				case 0:
					*op++ = ' ';
					break;
				case 1:
					if (i > 0 && (i & 1) == 1)
						*op++ = ' ';

					break;
				case 2:
					if (i > 0 && (i & 3) == 3)
						*op++ = ' ';

					break;
			}

			*op2++ = *p < ' ' || (*p > '~' && *p < '\xA0') ? '.' : *p;
			p++;
		}

		if (bsize > 8)
			switch (dtype) {
				case 0:
					ob[33] = '-';
					break;
				case 1:
					ob[29] = '-';
					break;
				case 2:
					ob[27] = '-';
					break;
			}

		for ( ; i < 16; i++)
			*op2++ = ' ';

		*op2 = '\0';
	}
	else
		ob[74] = '\0';

	PrintIText(Wnd->RPort,&ot,LeftBarSize+6,TopBarSize+20+lnum * lsize);
}

static void DispBuff(BOOL us)
{
	register int i,z;

	if (fptr) {
		Cursor(OFF);

		for (i = 0; i < 16; i++) {
			z = rb_size - (i << 4);

			if (z > 16)
				z = 16;

			if (z < 0)
				z = 0;

			DisplayLine(&rbuff[i<<4],z,i);
		}

		Cursor(ON);
	}

	if (us)
		SetScroller(coffs >> num_shf);
}

static void Cursor(BOOL state)
{
	static UBYTE obx[4],ob[4];
	static struct IntuiText ot = {1,0,JAM2,0,0,&topaz11,obx,NULL};
	struct RastPort *rp;
	int x1,x2,y1;
	UBYTE byte;
	BOOL changed;

	if (fptr) {
		rp = Wnd->RPort;
		SetDrMd(rp,JAM2);
		byte = rbuff[cx + (cy << 4)];
		changed = (byte != ubuff[cx + (cy << 4)]);

		if (mode == ASC)
			hcx = 0;

		ob[0] = hex_str[byte>>4];
		ob[1] = hex_str[0x0f & byte];
		ob[2] = '\0';

		if (byte < 32 || (byte > 127 && byte < 160))
			ob[2] = '.';
		else
			ob[2] = byte;

		if (changed)
			ot.FrontPen = 2;
		else
			ot.FrontPen = 1;

		x1 = LeftBarSize + 86 + cx * 16;
		x2 = LeftBarSize + 470 + cx * 8;

		switch (dtype) {
			case 0:
				x1 += cx * 8;
				break;
			case 1:
				x1 += (cx >> 1) * 8;
				x2 -= 64;
				break;
			case 2:
				x1 += (cx >> 2) * 8;
				x2 -= 96;
				break;
		}

		y1 = TopBarSize + 20 + cy * lsize;
		ot.BackPen = 0;
		obx[0] = ob[0];
		obx[1] = ob[1];
		obx[2] = '\0';
		PrintIText(rp,&ot,x1,y1);
		obx[0] = ob[2];
		obx[1] = '\0';
		PrintIText(rp,&ot,x2,y1);

		if (state) {
			ot.BackPen = 3;

			if (mode == HEX) {
				ot.FrontPen = 1;
				obx[0] = ob[hcx];
				obx[1] = '\0';
				PrintIText(rp,&ot,x1+8*hcx,y1);
			}
			else {
				ot.FrontPen = 0;
				obx[0] = ob[0];
				obx[1] = ob[1];
				obx[2] = '\0';
				PrintIText(rp,&ot,x1,y1);
			}

			if (mode == ASC)
				ot.FrontPen = 1;
			else
				ot.FrontPen = 0;

			obx[0] = ob[2];
			obx[1] = '\0';
			PrintIText(rp,&ot,x2,y1);
		}
	}
}

static void Resume(char *title,char *strmsg,BOOL dg)
{
	struct EasyStruct res;
	ULONG iflags;
	char ttl[80];
	int i;

	strcpy(ttl,GetLangStr(MSG_FILEZAP_TITLE));

	if (title != NULL) {
		strcat(ttl,": ");
		strcat(ttl,title);
	}

	res.es_StructSize = sizeof(struct EasyStruct);
	res.es_Flags = 0;
	res.es_Title = ttl;
	res.es_TextFormat = strmsg;
	res.es_GadgetFormat = "   Ok   ";
	iflags = NULL;

	if (dg) {
		for (i = GD_First; i <= GD_Last; i++)
			GT_SetGadgetAttrsA(Gadgets[i],Wnd,NULL,DisableTags);

		ClearMenuStrip(Wnd);
	}

	run_pros++;
	EasyRequestArgs(Wnd,&res,&iflags,NULL);
	run_pros--;

	if (dg) {
		for (i = GD_First; i <= GD_Last; i++)
			GT_SetGadgetAttrsA(Gadgets[i],Wnd,NULL,EnableTags);

		SetMenuStrip(Wnd,Menus);
	}
}

static __saveds void About(void)
{
	Resume(GetLangStr(MSG_ABOUT_1),GetLangStr(MSG_ABOUT_2),FALSE);
}

static __saveds void Help(void)
{
	Resume(GetLangStr(MSG_HELP_1),GetLangStr(MSG_HELP_2),FALSE);
}

static void SetDispMode(void)
{
	if (mode == HEX)
		strcpy(mode_str,"HEX");
	else
		strcpy(mode_str,"ASC");

	if (Wnd)
		GT_SetGadgetAttrsA(Gadgets[GD_Mode],Wnd,NULL,ModeStrTags);
}

static void DoOpenFile(void)
{
	BPTR tptr;

	if (tptr = Open(fname,MODE_OLDFILE)) {
		if (fptr) {
			CheckChange();
			Close(fptr);
		}

		fptr = tptr;
		Seek(fptr,0,OFFSET_END);
		fsize = Seek(fptr,0,OFFSET_BEGINNING);
		coffs = cx = cy = hcx = 0;
		num_shf = 3;

		do {
			num_shf++;
			num_lines = (fsize >> num_shf) + ((fsize & ((1 << num_shf) - 1)) > 0);
		} while (num_lines > 32767);

		mode = HEX;
		DispSize();
	 	GT_SetGadgetAttrsA(Gadgets[GD_FName],Wnd,NULL,FNameTags);
		ReadBuff();
		DispBuff(TRUE);
	}
}

static void DispSize(void)
{
	tsprintf(fs_str,"%9lU ($%06lx)",(LONG)fsize,(LONG)fsize);

	if (fs_str[5] != ' ') {
		fs_str[6] = '.';

		if (fs_str[1] != ' ')
			fs_str[2] = '.';
	}

	GT_SetGadgetAttrsA(Gadgets[GD_FSize],Wnd,NULL,FSStrTags);
}

static void ReadBuff(void)
{
	Seek(fptr,coffs,OFFSET_BEGINNING);
	rb_size = Read(fptr,rbuff,256);
	memcpy(ubuff,rbuff,rb_size);
}

static void SaveFile(void)
{
	if (fptr) {
		if (memcmp(rbuff,ubuff,rb_size) != 0) {
			Seek(fptr,coffs,OFFSET_BEGINNING);
			Write(fptr,rbuff,rb_size);
			movmem(rbuff,ubuff,rb_size);
			DispBuff(TRUE);
		}
	}
	else
		Beep();
}

static void RestoreBuffer(void)
{
	if (fptr) {
		if (memcmp(rbuff,ubuff,rb_size) != 0) {
			movmem(ubuff,rbuff,rb_size);
			DispBuff(TRUE);
		}
	}
	else
		Beep();
}

static void CheckChange(void)
{
	char tempstr[80];
	struct EasyStruct trs;
	ULONG iflags;
	int i;

	if (memcmp(rbuff,ubuff,rb_size) != 0) {
		trs.es_StructSize = sizeof(struct EasyStruct);
		trs.es_TextFormat = GetLangStr(MSG_BUFF_CHANGE);
		trs.es_GadgetFormat = GetLangStr(MSG_SAVE_IGNORE);
		strcpy(tempstr,GetLangStr(MSG_FILEZAP_TITLE));
		strcat(tempstr,": ");
		strcat(tempstr,GetLangStr(MSG_WARNING));
		trs.es_Title = tempstr;
		trs.es_Flags = 0;
		iflags = NULL;

		for (i = GD_First; i <= GD_Last; i++)
			GT_SetGadgetAttrsA(Gadgets[i],Wnd,NULL,DisableTags);

		ClearMenuStrip(Wnd);

		if (EasyRequestArgs(Wnd,&trs,&iflags,NULL) == 1) {
			Seek(fptr,coffs,OFFSET_BEGINNING);
			Write(fptr,rbuff,rb_size);
			movmem(rbuff,ubuff,rb_size);
		}
		else
			movmem(ubuff,rbuff,rb_size);

		DispBuff(TRUE);

		for (i = GD_First; i <= GD_Last; i++)
			GT_SetGadgetAttrsA(Gadgets[i],Wnd,NULL,EnableTags);

		SetMenuStrip(Wnd,Menus);
	}
}

static void SetScroller(long top)
{
	ScrollTags2[0].ti_Data = top;
	ScrollTags2[1].ti_Data = num_lines;
	ScrollTags2[2].ti_Data = 16;
	GT_SetGadgetAttrsA(Gadgets[GD_Scroller],Wnd,NULL,ScrollTags2);
}

static void DoScroller(ULONG lnum)
{
	CheckChange();

	coffs = lnum << num_shf;
	ReadBuff();
	DispBuff(FALSE);
}

static void Beep(void)
{
	DisplayBeep(Wnd->WScreen);
}

static void ScrollDown(void)
{
	int z;

	ScrollRaster(Wnd->RPort,0,-lsize,LeftBarSize+6,TopBarSize+20,LeftBarSize+598,TopBarSize+194+soffs);

	z = rb_size;

	if (z > 16)
		z = 16;

	DisplayLine(&rbuff[0],z,0);
	SetScroller(coffs >> num_shf);
}

static void ScrollUp(void)
{
	int z;

	ScrollRaster(Wnd->RPort,0,lsize,LeftBarSize+6,TopBarSize+20,LeftBarSize+598,TopBarSize+194+soffs);

	z = rb_size - 240;

	if (z < 0)
		z = 0;

	DisplayLine(&rbuff[240],z,15);
	SetScroller(coffs >> num_shf);
}

static void MoveLeft(void)
{
	Cursor(OFF);

	if (mode == HEX && hcx != 0)
		hcx = 0;
	else {
		if (cx > 0) {
			cx--;
			hcx = 1;
		}
		else {
			if (cy > 0) {
				cy--;
				cx = 15;

				if (mode == HEX)
					hcx = 1;
			}
			else {
				if (coffs > 15) {
					CheckChange();
					coffs -= 16;
					ReadBuff();
					ScrollDown();
					cx = 15;

					if (mode == HEX)
						hcx = 1;
				}
				else
					Beep();
			}
		}
	}

	Cursor(ON);
}

static void MoveRight(void)
{
	Cursor(OFF);

	if (mode == HEX && hcx == 0)
		hcx++;
	else {
		if (cx < 15 && (coffs + (cy << 4) + cx + 1) < fsize) {
			cx++;
			hcx = 0;
		}
		else {
			if (cx < 15)
				Beep();
			else {
				if ((cy + 1 + (coffs >> num_shf)) <= num_lines) {
					cx = 0;
					hcx = 0;

					if (cy < 15)
						cy++;
					else {
						CheckChange();
						coffs += 16;
						ReadBuff();
						ScrollUp();
					}
				}
				else
					Beep();
			}
		}
	}

	Cursor(ON);
}

static void MoveUp(void)
{
	Cursor(OFF);

	if (cy > 0)
		cy--;
	else
		if (coffs > 15) {
			CheckChange();
			coffs -= 16;
			ReadBuff();
			ScrollDown();
		}
		else
			Beep();

	Cursor(ON);
}

static void MoveDown(void)
{
	Cursor(OFF);

	if ((coffs + (cy << 4) + cx + 16) < fsize) {
		if (cy < 15)
			cy++;
		else {
			CheckChange();
			coffs += 16;
			ReadBuff();
			ScrollUp();
		}
	}
	else
		Beep();

	Cursor(ON);
}

#define SB_SIZE 4096

static void DoTheSearch(void)
{
	UBYTE *sb,tempstr[80];
	int search_pos;
	int search_left;
	BOOL result = FALSE;
	BOOL keypressed = FALSE;
	int i;

	if ((sb = AllocMem(SB_SIZE,MEMF_PUBLIC)) == NULL) {
		Resume(GetLangStr(MSG_SSEARCH),GetLangStr(MSG_SSEARCH_NO_MEM),TRUE);
		return;
	}

	CheckChange();
	Cursor(FALSE);
	SetPointer(Wnd,(short *)&WaitSpriteData,25,16,-8,-12);
	search_pos = coffs + (cy << 4) + cx;
	strcpy(tempstr,GetLangStr(MSG_FILEZAP_TITLE));
	strcat(tempstr,": ");
	strcat(tempstr,GetLangStr(MSG_STOP_SEARCH));
	SetWindowTitles(Wnd,tempstr,(UBYTE *)-1L);

	if (search_forward) {
		search_pos++;

		if (search_pos + slen <= fsize) {
			do {
				if (keypressed = check_key())
					break;

				if ((search_left = (fsize - search_pos)) > SB_SIZE)
					search_left = SB_SIZE;

				if (search_left < slen)
					break;

				Seek(fptr,search_pos,OFFSET_BEGINNING);
				Read(fptr,sb,search_left);

				for (i = 0; i <= (search_left - slen); i++)
					if (CompMem(&sb[i],sstr,slen) == TRUE) {
						result = TRUE;
						search_pos += i;
						break;
					}

				if (result)
					break;

				search_pos += (search_left - slen);
			} while ((search_pos + slen) < fsize);
		}
	}
	else {
		if (search_pos >= slen) {
			search_pos -= slen;

			do {
				if (keypressed = check_key())
					break;

				if ((search_left = search_pos) > SB_SIZE)
					search_left = SB_SIZE;

				if (search_pos + slen <= SB_SIZE)
					search_pos = 0;
				else
					search_pos -= (search_left - slen);

				if (search_left <= slen || search_pos < 0)
					search_pos = 0;

				Seek(fptr,search_pos,OFFSET_BEGINNING);
				Read(fptr,sb,search_left);

				for (i = (search_left - slen); i >= 0; i--)
					if (CompMem(&sb[i],sstr,slen) == TRUE) {
						result = TRUE;
						search_pos += i;
						break;
					}
			} while (search_pos > 0 && result == FALSE);
		}
	}

	ClearPointer(Wnd);
	SetWindowTitles(Wnd,GetLangStr(MSG_FILEZAP_TITLE),(UBYTE *)-1L);

	if (keypressed) {
		Resume(GetLangStr(MSG_SSEARCH),GetLangStr(MSG_SSEARCH_INT),TRUE);

		if (search_pos < (coffs = ((fsize - 1) & 0x7FFFFFF0) - 240))
			coffs = search_pos & 0x7FFFFFF0;

		search_pos -= coffs;
		cx = search_pos & 0x0F;
		cy = search_pos >> 4;
		ReadBuff();
		DispBuff(TRUE);
	}
	else if (result) {
		if (search_pos < (coffs = ((fsize - 1) & 0x7FFFFFF0) - 240))
			coffs = search_pos & 0x7FFFFFF0;

		search_pos -= coffs;
		cx = search_pos & 0x0F;
		cy = search_pos >> 4;
		ReadBuff();
		DispBuff(TRUE);
	}
	else {
		Resume(GetLangStr(MSG_SSEARCH),GetLangStr(MSG_SSEARCH_NOT_FOUND),TRUE);
		Cursor(TRUE);
	}

	FreeMem(sb,SB_SIZE);
}

static BOOL CompMem(register UBYTE *block1,register UBYTE *block2,register int size)
{
	register int i;

	if (!scase_dep)
		for (i = 0; i < size; i++) {
			if (trans_table[*block1++] != trans_table[*block2++])
				return(FALSE);
		}
	else
		for (i = 0; i < size; i++)
			if (*block1++ != *block2++)
				return(FALSE);

	return(TRUE);
}

static BOOL check_key(void)
{
	struct IntuiMessage *msg;
	register LONG cclass;
	register USHORT ccode;

	if ((msg = GT_GetIMsg(Wnd->UserPort)) != NULL) {
		cclass = msg->Class;
		ccode = msg->Code;
		GT_ReplyIMsg(msg);

		if (cclass & RAWKEY)
			if (ccode < 0x5F)
				return(TRUE);
	}

	return(FALSE);
}

static void InsertBytes(int size)
{
	UBYTE *m;
	int zx,cs;

	if (fptr) {
		CheckChange();
		zx = coffs + (cy << 4) + cx;
		cs = fsize - zx;

		if (m = AllocMem(cs,MEMF_PUBLIC)) {
			Seek(fptr,zx,OFFSET_BEGINNING);

			if (Read(fptr,m,cs) == cs) {
				Seek(fptr,zx+size,OFFSET_BEGINNING);
				Write(fptr,m,cs);
				Seek(fptr,zx,OFFSET_BEGINNING);
				memset(m,0,size);
				Write(fptr,m,size);
				fsize += size;
			}

			FreeMem(m,cs);
			DispSize();
			ReadBuff();
			DispBuff(TRUE);
		}
		else
			Resume(GetLangStr(MSG_INSERT),GetLangStr(MSG_INSERT_NO_MEM),TRUE);
	}
	else
		Beep();
}

static void DeleteBytes(int size)
{
	UBYTE *m;
	int zx,cs;

	if (fptr) {
		CheckChange();
		zx = coffs + (cy << 4) + cx;
		cs = fsize - (zx + size);

		if (m = AllocMem(cs,MEMF_PUBLIC)) {
			Seek(fptr,zx + size,OFFSET_BEGINNING);

			if (Read(fptr,m,cs) == cs) {
				Seek(fptr,zx,OFFSET_BEGINNING);
				Write(fptr,m,cs);
				fsize -= size;
				SetFileSize(fptr,fsize,OFFSET_BEGINNING);
			}

			FreeMem(m,cs);
			DispSize();
			ReadBuff();
			DispBuff(TRUE);
		}
		else
			Resume(GetLangStr(MSG_DELETE),GetLangStr(MSG_DELETE_NO_MEM),TRUE);
	}
	else
		Beep();
}

static void MoveStart(void)
{
	CheckChange();
	coffs = 0;
	cx = cy = hcx = 0;
	ReadBuff();
	DispBuff(TRUE);
}

static void MoveEnd(void)
{
	CheckChange();

	if (fsize <= 256)
		coffs = 0;
	else
		coffs = ((fsize - 1) & 0x7FFFFFF0) - 240;

	cy = fsize - coffs - 1;
	cx = cy & 0x0F;
	cy >>= 4;
	hcx = 0;
	ReadBuff();
	DispBuff(TRUE);
}

void main(int argc,char *argv[])
{
	struct IntuiMessage *msg;
	struct InputEvent ie;
	struct MenuItem *item;
	struct Gadget *ga;
	UBYTE keybuff[10];
	ULONG class;
	USHORT code,qualifier;
	WORD mx,my;
	BOOL done,chf;
	UBYTE ch,kkey;
	int i,j,k,nchars;
	int ibsize,dbsize;
	int bvsize;

	if (!InitStuff()) {
		done = FALSE;

		if (argc != 0) {
			if (argc == 2) {
				strcpy(fname,argv[1]);
				DoOpenFile();

				if (fptr == NULL)
					Resume(GetLangStr(MSG_FILE_OPEN),GetLangStr(MSG_FILE_OPEN_NO_FILE),TRUE);
			}
		}

		bvsize = 0;

		do {
			Wait(1 << Wnd->UserPort->mp_SigBit | 1 << AppMPort->mp_SigBit);

			while (msg = GT_GetIMsg(Wnd->UserPort)) {
				class = msg->Class;
				code = msg->Code;
				qualifier = msg->Qualifier;
				ga = (struct Gadget *)msg->IAddress;
				mx = msg->MouseX;
				my = msg->MouseY;

				switch (class) {
					case IDCMP_CLOSEWINDOW:
						if (fptr)
							CheckChange();

						done = TRUE;
						break;
					case IDCMP_REFRESHWINDOW:
						GT_BeginRefresh(Wnd);
						DrawBevelBoxA(Wnd->RPort,LeftBarSize+2,TopBarSize+17,602-bvsize,181+soffs,BevelTags);
						DrawBevelBoxA(Wnd->RPort,LeftBarSize+4,TopBarSize+18,598-bvsize,179+soffs,BevelTags2);
						DispBuff(TRUE);
						GT_EndRefresh(Wnd,TRUE);
						break;
					case IDCMP_MOUSEMOVE:
						if (fptr != NULL && ga != NULL && ga->GadgetID == GD_Scroller)
							DoScroller((ULONG)code);

						break;
					case IDCMP_GADGETDOWN:
						if (ga->GadgetID == GD_Scroller)
							if (fptr)
								DoScroller((ULONG)code);
							else
								Beep();

						break;
					case IDCMP_GADGETUP:
						switch (ga->GadgetID) {
							case GD_FName:
								strcpy(fname,((struct StringInfo *)(ga->SpecialInfo))->Buffer);
								DoOpenFile();
								break;
							case GD_SearchStr:
								strcpy(sstr,((struct StringInfo *)(ga->SpecialInfo))->Buffer);

								if ((i = strlen(sstr)) > 0) {
									if (sstr[0] == '$') {
										if (i > 1) {
											if (--i & 1) {
												strcpy(tstr,&sstr[1]);
												sstr[1] = '0';
												sstr[2] = '\0';
												strcat(sstr,tstr);
											}

											for (k = 0,j = 1,chf = TRUE; j <= i; ) {
												while ((ch = sstr[j++]) == ' ');

												ch -= '0';

												if (ch > 9)
													ch -= 7;

												if (chf)
													sstr[k] = ch << 4;
												else
													sstr[k++] |= ch;

												chf = !chf;
											}

											slen = k + (chf == FALSE);
										}
									}
									else
										slen = i;

									searching = TRUE;
									DoTheSearch();
								}
								else
									searching = FALSE;

								break;
							case GD_Scroller:
								if (fptr)
									DoScroller((ULONG)code);
								else
									Beep();

								break;
							case GD_Start:
								if (fptr)
									MoveStart();
								else
									Beep();

								break;
							case GD_End:
								if (fptr)
									MoveEnd();
								else
									Beep();

								break;
							case GD_Save:
								if (fptr)
									SaveFile();
								else
									Beep();

								break;
							case GD_Undo:
								if (fptr)
									RestoreBuffer();
								else
									Beep();

								break;
							case GD_SSearch:
								if (fptr) {
									if (searching)
										DoTheSearch();
									else
										Resume(GetLangStr(MSG_SSEARCH),GetLangStr(MSG_SSEARCH_NO_STRING),TRUE);
								}
								else
									Beep();

								break;
							case GD_Quit:
								if (fptr)
									CheckChange();

								done = TRUE;
								break;
							case GD_Goto:
								if (fptr) {
									strcpy(gstr,((struct StringInfo *)(ga->SpecialInfo))->Buffer);

									if (strlen(gstr) > 0) {
										if (gstr[0] == '$')
											stch_i(&gstr[1],&goto_offs);
										else
											stcd_i(gstr,&goto_offs);

										if (goto_offs < fsize) {
											CheckChange();
											coffs = goto_offs & 0x7FFFFFF0;
											cy = hcx = 0;
											cx = goto_offs & 15;
											ReadBuff();
											DispBuff(TRUE);
										}
										else
											Beep();
									}
								}
								else
									Beep();

								break;
							case GD_SearchBack:
								search_forward = !search_forward;
								break;
							case GD_CaseSense:
								scase_dep = !scase_dep;
								break;
						}

						break;
					case IDCMP_MENUPICK:
						while ((USHORT)code != MENUNULL) {
							item = ItemAddress(Menus,code);

							switch (MENUNUM(code)) {
								case 0:								// Project
									switch (ITEMNUM(code)) {
										case 0:						// Open
											CheckChange();

											if (RequestFile(FReq)) {
												if (strlen(FReq->fr_Drawer) > 0)
													strcpy(fname,FReq->fr_Drawer);
												else
													fname[0] = '\0';

												if (strlen(fname) > 0)
													if (fname[strlen(fname)-1] != ':')
														strcat(fname,"/");

												strcat(fname,FReq->fr_File);

												if (strlen(fname) > 0)
													DoOpenFile();
											}

											break;
										case 1:						// Save
											if (fptr)
												SaveFile();
											else
												Beep();

											break;
										case 2:						// Goto
											if (fptr) {
												CheckChange();
												ActivateGadget(Gadgets[GD_Goto],Wnd,NULL);
											}
											else
												Beep();

											break;
										case 4:						// New Shell
											Execute("NewShell WINDOW \"CON:0/11/640/189/AmigaShell/AUTO/CLOSE\"",NULL,NULL);
											break;
										case 5:						// Help
											CreateNewProc(HelpTags);
											break;
										case 6:						// About
											CreateNewProc(AboutTags);
											break;
										case 7:						// Quit
											if (fptr)
												CheckChange();

											done = TRUE;
											break;
									}

									break;
								case 1:
									switch (ITEMNUM(code)) {
										case 0:						// Undo
											if (fptr)
												RestoreBuffer();
											else
												Beep();

											break;
										case 1:						// Insert
											switch (SUBNUM(code)) {
												case 0:				// 1 Byte
													ibsize = 1;
													break;
												case 1:				// 1 Word
													ibsize = 2;
													break;
												case 2:				// 1 Long
													ibsize = 4;
													break;
												case 3:				// 4 Longs
													ibsize = 16;
													break;
												default:
													ibsize = 0;
													break;
											}

											if (ibsize)
												InsertBytes(ibsize);

											break;
										case 2:						// Delete
											switch (SUBNUM(code)) {
												case 0:				// 1 Byte
													dbsize = 1;
													break;
												case 1:				// 1 Word
													dbsize = 2;
													break;
												case 2:				// 1 Long
													dbsize = 4;
													break;
												case 3:				// 4 Longs
													dbsize = 16;
													break;
												default:
													dbsize = 0;
													break;
											}

											if (dbsize)
												DeleteBytes(dbsize);

											break;
										case 3:						// Display
											switch (SUBNUM(code)) {
												case 0:				// Byte
													dtype = 0;
													bvsize = 0;
													break;
												case 1:				// Word
													dtype = 1;
													bvsize = 64;
													break;
												case 2:				// Long
													dtype = 2;
													bvsize = 96;
													break;
											}

											SetDrMd(Wnd->RPort,JAM2);
											SetAPen(Wnd->RPort,0);
											RectFill(Wnd->RPort,LeftBarSize+2,TopBarSize+17,LeftBarSize+603,TopBarSize+197+soffs);
											DrawBevelBoxA(Wnd->RPort,LeftBarSize+2,TopBarSize+17,602-bvsize,181+soffs,BevelTags);
											DrawBevelBoxA(Wnd->RPort,LeftBarSize+4,TopBarSize+18,598-bvsize,179+soffs,BevelTags2);
											DispBuff(TRUE);
											break;
									}

									break;
								case 2:
									switch (ITEMNUM(code)) {
										case 0:						// Search for...
											if (fptr)
												ActivateGadget(Gadgets[GD_SearchStr],Wnd,NULL);

											break;
										case 1:						// Continue Search
											if (fptr) {
												if (searching)
													DoTheSearch();
												else
													Resume(GetLangStr(MSG_SSEARCH),GetLangStr(MSG_SSEARCH_NO_STRING),TRUE);
											}
											else
												Beep();

											break;
									}
							}

							code = item->NextSelect;
						}

						break;
					case IDCMP_RAWKEY:
						switch (code) {
							case 0x60:
							case 0x61:
								shift = TRUE;
								break;
							case 0x63:
								ctrl = TRUE;
								break;
							case 0xE0:
							case 0xE1:
								shift = FALSE;
								break;
							case 0xE3:
								ctrl = FALSE;
								break;
							case 0x5F:
								CreateNewProc(HelpTags);
								break;
							case 0x42:
								if (fptr) {
									if (mode == HEX)
										mode = ASC;
									else
										mode = HEX;

									SetDispMode();
									Cursor(ON);
								}

								break;
							case CURSORUP:
								if (fptr) {
									if (ctrl == TRUE && shift == FALSE) {
										MoveStart();
									}
									else if (ctrl == FALSE && shift == TRUE) {
										CheckChange();

										if (coffs > 255)
											coffs -= 256;
										else
											coffs = 0;

										ReadBuff();
										DispBuff(TRUE);
									}
									else if (ctrl == FALSE && shift == FALSE)
										MoveUp();
									else
										Beep();
								}

								break;
							case CURSORDOWN:
								if (fptr) {
									if (ctrl == TRUE && shift == FALSE) {
										MoveEnd();
									}
									else if (ctrl == FALSE && shift == TRUE) {
										CheckChange();

										if ((coffs + 512) < fsize)
											coffs += 256;
										else if (fsize > 256)
											coffs = ((fsize - 1) & 0x7FFFFFF0) - 240;
										else
											coffs = 0;

										ReadBuff();
										DispBuff(TRUE);
									}
									else if (ctrl == FALSE && shift == FALSE)
										MoveDown();
									else
										Beep();
								}

								break;
							case CURSORLEFT:
								if (fptr) {
									if (ctrl == FALSE && shift == TRUE) {
										Cursor(OFF);
										cx = hcx = 0;
										Cursor(ON);
									}
									else
										MoveLeft();
								}

								break;
							case CURSORRIGHT:
								if (fptr) {
									if (ctrl == FALSE && shift == TRUE) {
										Cursor(OFF);

										if ((coffs + 15 + (cy << 4)) >= fsize)
											cx = (fsize - 1) & 0x0F;
										else
											cx = 15;

										hcx = 1;
										Cursor(ON);
									}
									else
										MoveRight();
								}

								break;
							default:
								if (fptr) {
									if (code < 0x60) {
										ie.ie_Class = IECLASS_RAWKEY;
										ie.ie_SubClass = 0;
										ie.ie_Code = msg->Code;
										ie.ie_Qualifier = msg->Qualifier;
										ie.ie_EventAddress = (APTR)msg->IAddress;
										nchars = MapRawKey(&ie,keybuff,sizeof(keybuff),0);

										if (nchars == 1) {
											kkey = keybuff[0];

											if (mode == HEX) {
												if (kkey >= 'a' && kkey <= 'z')
													kkey -= ' ';
												if ((kkey >= '0' && kkey <= '9') ||
													(kkey >= 'A' && kkey <= 'F')) {
													kkey -= '0';
													if (kkey > 9)
														kkey -= 7;
													if (hcx) {
														rbuff[(cy << 4) + cx] &= 0xF0;
														rbuff[(cy << 4) + cx] |= kkey;
													}
													else {
														rbuff[(cy << 4) + cx] &= 0x0F;
														rbuff[(cy << 4) + cx] |= kkey << 4;
													}
													MoveRight();
												}
												else
													Beep();
											}
											else {
												rbuff[(cy << 4) + cx] = kkey;
												MoveRight();
											}
										}
										else
											Beep();
									}
								}
								else
									Beep();

								break;
						}

						break;
					case IDCMP_MOUSEBUTTONS:
						if ((qualifier & IEQUALIFIER_LEFTBUTTON) != 0 && fptr != NULL)
							if (mx > (LeftBarSize + 85) && mx < (LeftBarSize + 597) &&
								my > (TopBarSize + 19) && my < (TopBarSize + 20+(lsize*16)) && 
								fptr != NULL) {
								mx = (mx - (LeftBarSize + 86)) >> 3;
								my = (my - (TopBarSize + 20)) / lsize;
								switch (dtype) {
									case 0:
										if (mx > 47 && mx < 64) {
											Cursor(OFF);
											cx = mx - 48;
											cy = my;
											hcx = 0;
											mode = ASC;
											Cursor(ON);
											SetDispMode();
											break;
										}
										else if ((mx % 3) != 2) {
											Cursor(OFF);
											cx = mx / 3;
											hcx = mx % 3;
											cy = my;
											mode = HEX;
											Cursor(ON);
										}

										break;
									case 1:
										if (mx > 39 && mx < 56) {
											Cursor(OFF);
											cx = mx - 40;
											cy = my;
											hcx = 0;
											mode = ASC;
											Cursor(ON);
											SetDispMode();
											break;
										}
										else if ((mx % 5) != 4 && mx < 39) {
											Cursor(OFF);
											cx = (mx / 5) * 2 + ((mx % 5) > 1);
											hcx = (mx % 5) & 1;
											cy = my;
											mode = HEX;
											Cursor(ON);
										}

										break;
									case 2:
										if (mx > 35 && mx < 52) {
											Cursor(OFF);
											cx = mx - 36;
											cy = my;
											hcx = 0;
											mode = ASC;
											Cursor(ON);
											SetDispMode();
											break;
										}
										else if ((mx % 9) != 8 && mx < 35) {
											Cursor(OFF);
											cx = (mx / 9) * 4 + ((mx % 9) / 2);
											hcx = (mx % 9) & 1;
											cy = my;
											mode = HEX;
											Cursor(ON);
										}

										break;
								}

								SetDispMode();
							}

						break;
				}

				GT_ReplyIMsg(msg);
			}

			while (AMsg = (struct AppMessage *)GetMsg(AppMPort)) {
				if (AMsg->am_NumArgs > 0)
					if (NameFromLock(AMsg->am_ArgList->wa_Lock,fname,sizeof(fname)))
						if (strlen(fname) > 0) {
							if (fname[strlen(fname)-1] != ':')
								strcat(fname,"/");

							strcat(fname,AMsg->am_ArgList->wa_Name);
							DoOpenFile();
							ActivateWindow(Wnd);
							WindowToFront(Wnd);
						}

				ReplyMsg((struct Message *)AMsg);
			}
		} while (!done);
	}

	CleanStuff();
}
