.c.o:
/*********************************************
 *															*
 *	Editor												*
 *															*
 *	Text editor for book Adv_C.	*
 *															*
 *	© 1988 DATA	BECKER		ABACUS						*
 *															*
 *********************************************/
/*#FOLD:	Includes	*/
/************
 *
 * Includes:
 *
 ************/

#include <exec/types.h>
#include	<intuition/intuitionbase.h>
#include	<intuition/intuition.h>
#include	"src/Editor.h"
/*#ENDFD*/
/*#FOLD:	Defines */
/***********
 *
 * Defines:
 *
 ***********/

#define REV 33L
#define MAXINPUTLEN 128L
#define UT1 "USAGE: Editor [Flags] <Filename>"
#define UT2 "       Flags: [-a][-A][-b][-B][- i|I][- o|O][- r|R[=n]][-t][-T]"
/*#ENDFD*/
/*#FOLD:	External Functions */
/**********************
 *
 * External Functions:
 *
 **********************/

struct Library *OpenLibrary();
struct Window *OpenWindow();
void CloseLibrary(),NewList(),AddTail(),CloseWindow(),free();
void DeletePort(),ModifyIDCMP(),ReplyMsg(),freeMemoryblock();
void initWindowSize(),SetDrMd(),SetAPen(),SetBPen(),printAll();
void Cursor(),saveIfCursorMoved(),strncpy(),CloseFont(),puts();
void printXpos(),printYpos(),printInfo(),DisplayBeep();
void BeginRefresh(),EndRefresh();
struct Editor *malloc(),*RemHead();
struct MsgPort *CreatePort();
struct IntuiMessage *GetMsg();
ULONG Wait(),OpenDevice();
SHORT RawKeyConvert();
struct TextFont *OpenFont();
BOOL handleKeys(),ActivateGadget(),loadASCII();
UBYTE	*executeCommand(),*commandSet();
/*#ENDFD*/
/*#FOLD:	Global Variables	*/
/*********************
 *
 * Global Variables:
 *
 *********************/ 

struct Library *IntuitionBase = NULL, *GfxBase = NULL, *DosBase = NULL;
struct Device *ConsoleDevice = NULL;

struct EList editorList;
struct Editor *actualEditor;

/*#FOLD: Window und Gadgets */
UBYTE gc_SIBuffer[256];
UBYTE gc_UndoBuffer[256];
struct StringInfo gc_GadgetSI =
{
	gc_SIBuffer,
	gc_UndoBuffer,
	0,
	256,
	0,
	0,0,0,0,0,
	0,
	NULL,
	NULL
};

SHORT gc_BorderVectors[4] = {0,0,350,0};
struct Border gc_Border =
{
	-1,-1,
	1,0,JAM1,
	2,
	gc_BorderVectors,
	NULL
};

struct Gadget G_Command =
{
	NULL,
	2,-9,
	-302,9,
	GADGHCOMP | GRELBOTTOM | GRELWIDTH,
	RELVERIFY | BOTTOMBORDER,
	STRGADGET,
	(APTR)&gc_Border,
	NULL,
	NULL,
	0,
	(APTR)&gc_GadgetSI,
	2,
	NULL
};

SHORT gi_BorderVectors[14] = {-1,0,-1,10,0,10,0,0,298,0,298,1,283,1};
struct Border gi_Border =
{
	0,0,
	1,0,JAM1,
	7,
	gi_BorderVectors,
	NULL
};

struct TextAttr TOPAZ80 =
{
	(STRPTR)"topaz.font",
	TOPAZ_EIGHTY,0,0
};

UBYTE gi_Text[36] = "X=   1 Y=   1 #=   0 [ 0, 0] IcATB";
struct IntuiText gi_IText =
{
	1,0,JAM2,
	4,2,
	&TOPAZ80,
	gi_Text,
	NULL
};

struct Gadget G_Info =
{
	&G_Command,
	-298,-10,
	280,10,
	GADGHNONE | GRELBOTTOM | GRELRIGHT,
	RELVERIFY | BOTTOMBORDER,
	BOOLGADGET,
	(APTR)&gi_Border,
	NULL,
	&gi_IText,
	0,
	NULL,
	1,
	NULL
};

struct NewWindow newEdWindow =
{
	0,0,640,200,
	AUTOFRONTPEN,AUTOBACKPEN,
	REFRESHWINDOW | MOUSEBUTTONS | RAWKEY | CLOSEWINDOW | NEWSIZE | GADGETUP,
	WINDOWSIZING | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SIZEBBOTTOM
	| SIMPLE_REFRESH | ACTIVATE,
	NULL,NULL,
	NULL,
	NULL,NULL,
	320,50,640,200,
	WBENCHSCREEN
};

struct TextFont *infoFont = NULL;
/*#ENDFD*/

struct MsgPort *edUserPort = NULL;

struct IOStdReq ioStdReq;

UBYTE inputBuffer[MAXINPUTLEN];
UWORD inputLen = 0;

struct InputEvent inputEvent =
{
	0,
	IECLASS_RAWKEY,0,
	0,0
};
/*#ENDFD*/
/*#FOLD:	Functions */
/*#FOLD:	nextLine	*/
/*********************************************
 *
 * nextLine(line,pnr)
 *
 * Returns pointer to next line,
 * and executes folding
 * Zero, if no next line.
 *
 * line ^ line-structure.
 * pnr ^ to linenumber.
 *
 *********************************************/

struct Zline *nextLine(line,pnr)
register struct Zline *line;
register UWORD					 *pnr;
{
	register struct Zline *z;
	register UWORD minfold = actualEditor->minfold;
	register UWORD maxfold = actualEditor->maxfold;

	if (z = line)
		if (z->succ)
			do
			{
				if ((z = z->succ)->succ)
					if ((z->flags & ZLF_FOLD) < minfold)
					{
						/* Following lines lie outside of fold */
						z = NULL;
						break;
					}
					else
						*pnr += 1;
				else
				{
					/* no following line */
					z = NULL;
					break;
				}
			}
			while ((z->flags & ZLF_FOLD) > maxfold);
		else
			z = NULL;

	return (z);
}
/*#ENDFD*/
/*#FOLD:	prevLine	*/
/*******************************************
 *
 * prevLine(line,pnr)
 *
 * Returns pointer to previous line,
 * and executes folding
 * Zero, if no previous line.
 *
 * line ^ Zline-structure.
 * pnr ^ to line number.
 *
 *******************************************/

struct Zline *prevLine(line,pnr)
register struct Zline *line;
register UWORD					 *pnr;
{
	register struct Zline *z;
	register UWORD minfold = actualEditor->minfold;
	register UWORD maxfold = actualEditor->maxfold;

	if (z = line)
		if (z->pred)
			do
			{
				if ((z = z->pred)->pred)
					if ((z->flags & ZLF_FOLD) < minfold)
					{
						/* previous line lies outside fold */
						z = NULL;
						break;
					}
					else
						*pnr -= 1;
				else
				{
					/* no previous line */
					z = NULL;
					break;
				}
			}
			while ((z->flags & ZLF_FOLD) > maxfold);
		else
			z = NULL;

	return (z);
}
/*#ENDFD*/
/*#FOLD:	OpenEditor */
/***********************************
 *
 * OpenEditor()
 *
 * Open Editor window and
 * initalize Editor structure
 *
 * Returns pointer to Editor structure
 * or is zero in case of an error
 *
 ***********************************/

struct Editor *OpenEditor()
{
	register struct Editor *ed = NULL;
	register struct Window *wd;
	register struct RastPort *rp;
	ULONG flags;

	/* IDCMPFlags saved, sets it to zero in structure
		=> use your own UserPort! */
	flags = newEdWindow.IDCMPFlags;
	newEdWindow.IDCMPFlags = NULL;

	/* Memory for editor structure: */
	if (ed = malloc(sizeof(struct Editor)))
	{
		/* Gadgets initialization: */
		ed->gc_SIBuffer[0]	= 0;
		ed->gc_GadgetSI		= gc_GadgetSI;
		ed->G_Command			= G_Command;
		ed->gi_IText			= gi_IText;
		ed->G_Info				= G_Info;
		strncpy(ed->gi_Text,gi_Text,sizeof(ed->gi_Text));

		/* set pointer: */
		ed->gc_GadgetSI.Buffer		= ed->gc_SIBuffer;
		ed->G_Command.SpecialInfo	= (APTR) &(ed->gc_GadgetSI);
		ed->gi_IText.IText			= ed->gi_Text;
		ed->G_Info.NextGadget		= &(ed->G_Command);
		ed->G_Info.GadgetText		= &(ed->gi_IText);
		newEdWindow.FirstGadget		= &(ed->G_Info);
		newEdWindow.Title				= ed->filename;
		ed->filename[0]				= 0;

		/* Window open: */
		if (wd = OpenWindow(&newEdWindow))
		{
			ed->window = wd;
			ed->rp = (rp = wd->RPort);

			/* Write mode set: */
			SetDrMd(rp,JAM2);
			SetAPen(rp,FGPEN);
			SetBPen(rp,BGPEN);

			/* UserPort established: */
			wd->UserPort = edUserPort;
			ModifyIDCMP(wd,flags);

			/* Parameter initialization: */
			NewList(&(ed->block));
			NewList(&(ed->zlines));

			ed->num_lines	= 0;
			ed->actual		= NULL;
			ed->buflen		= 0;
			ed->bufypos		= 0;
			ed->buflastchar= ' ';
			ed->leftpos		= 0;
			ed->xpos			= 1;
			ed->ypos			= 1;
			ed->wdy			= 0;
			ed->changed		= 0;
			ed->insert		= 1;
			ed->tabs			= 1;
			ed->skipblanks	= 1;
			ed->autoindent	= 1;
			ed->minfold		= 0;
			ed->maxfold		= 0;
			ed->rm			= MAXWIDTH;

			{
				register UBYTE *ptr;
				register struct Zline **zptr;
				register UWORD n,*pnr;

				/* zlinesptr/nr-Array initialization: */
				for (n = 0, zptr = ed->zlinesptr, pnr = ed->zlinesnr;
						n < MAXHEIGHT; n++, zptr++, pnr++)
				{
					*zptr = NULL;
					*pnr	= 1;
				}

				/* Tab initialization: */
				ptr = ed->tabstring;
				*ptr++ = 1;
				for (n = 1; n < MAXWIDTH; n++)
					if (n % 3)
						*ptr++ = 1;
					else
						*ptr++ = 0;
			}

			{
				register struct Editor *oldae;

				ed->wch = 0;
				initWindowSize(ed);

				oldae				 = actualEditor;
				actualEditor = ed;
				printInfo();
				actualEditor = oldae;
			}
		}
		else
		{
			free(ed);
			ed = NULL;
		}
	}

	newEdWindow.IDCMPFlags = flags;
	return (ed);
}
/*#ENDFD*/
/*#FOLD:	CloseEditor	*/
/***************************
 *
 * CloseEditor(ed)
 *
 * Close editor window.
 *
 * ed ^ Editor structure.
 *
 ***************************/

void CloseEditor(ed)
struct Editor	 *ed;
{
	register struct Memoryblock *blk;

	/* Free first memory block: */
	while (blk = (struct Memoryblock *)RemHead(&(ed->block)))
		freeMemoryblock(blk);

	/* Then Close window: */
	ed->window->UserPort = NULL;
	CloseWindow(ed->window);
	free(ed);
}
/*#ENDFD*/
/*#ENDFD*/
/*#FOLD:	Main program */
/*****************
 *
 * Main program:
 *
 *****************/

main(argc,argv)
int  argc;
UBYTE		*argv[];
{
	register struct Editor *ed;
	BOOL running = TRUE;
	register struct IntuiMessage *imsg;
	ULONG signal,class,mouseX,mouseY;
	UWORD code,qualifier;
	APTR iaddress;

	/*	Was Editor started with "Editor ?" , the Text output */
	if	(argc	==	2)
		if	(*argv[1] == '?')
		{
			puts(UT1);
			puts(UT2);
			goto Ende;
		}

	/* Libraries open: */
	if ( !(IntuitionBase = OpenLibrary("intuition.library",REV)))
		goto Ende;
	if ( !(GfxBase = OpenLibrary("graphics.library",REV)))
		goto Ende;
	if ( !(DosBase = OpenLibrary("dos.library",REV)))
		goto Ende;
	if ( !(OpenDevice("console.device",-1L,&ioStdReq,0L)))
		ConsoleDevice = ioStdReq.io_Device;
	else
		goto Ende;

	/* Font for Infoline open: */
	if (! (infoFont = OpenFont(&TOPAZ80))) goto Ende;

	/* UserPort open */
	if (! (edUserPort = CreatePort(NULL,0L))) goto Ende;

	/*	Max height for window calculated: */
	newEdWindow.Height =	newEdWindow.MaxHeight =
				((struct	IntuitionBase *)IntuitionBase)->ActiveScreen->Height;

	/* Editor list initialization: */
	NewList(&editorList);

	/* Open first editor window: */
	if (ed = OpenEditor())
	{
		AddTail(&editorList,ed);
		actualEditor = ed;
	}
	else
		goto Ende;

	/* Command line reading: */
	if (argc >= 2)
	{
		register UWORD n = 1;

		while	(n	< argc)
		{
			if	(*argv[n] == '-')
			{
				if	(commandSet(argv[n] + 1) >= 0x80000000)
				{
					DisplayBeep(NULL);
					break;
				}
			}
			else
			{
				if	(loadASCII(argv[n]))
					printAll();
				else
					DisplayBeep(NULL);

				/*	File name end input! */
				n++;
				break;
			}

			n++;
		}

		if (n < argc)
		{
			/*	Error! */
			puts(UT1);
			puts(UT2);
			goto Ende;
		}
	}

	/*#FOLD:	Main loop */
	do
	{
		/* Set cursor: */
		Cursor();

		signal = Wait(1L << edUserPort->mp_SigBit);

		/* erase cursor again: */
		Cursor();

		while (imsg = GetMsg(edUserPort))
		{
			class			= imsg->Class;
			code			= imsg->Code;
			qualifier	= imsg->Qualifier;
			iaddress		= imsg->IAddress;
			mouseX		= imsg->MouseX;
			mouseY		= imsg->MouseY;

			ReplyMsg(imsg);

			/* Event processing: */
			switch (class)
			{
				case RAWKEY:
				{
					register struct IntuiMessage *im1,*im2;

					if (! (code & IECODE_UP_PREFIX))
					{
						inputEvent.ie_Code		= code;
						inputEvent.ie_Qualifier = qualifier;
						if ((inputLen = RawKeyConvert(
									&inputEvent,inputBuffer,MAXINPUTLEN,NULL)
									) >= 0)
							running = handleKeys(inputBuffer,inputLen);
					}

					/* run-on suppressed: */
					im1 = (struct IntuiMessage *)
							edUserPort->mp_MsgList.lh_Head;
					while (im2 = (struct IntuiMessage *)
									 im1->ExecMessage.mn_Node.ln_Succ)
					{
						if (im2->ExecMessage.mn_Node.ln_Succ == NULL) break;
						if (im1->Class != RAWKEY) break;
						if (!(im1->Qualifier & IEQUALIFIER_REPEAT)) break;
						if (im2->Class != RAWKEY) break;
						if (!(im2->Qualifier & IEQUALIFIER_REPEAT)) break;

						/* Message reply: */
						im1 = GetMsg(edUserPort);
						ReplyMsg(im1);

						im1 = (struct IntuiMessage *)
								edUserPort->mp_MsgList.lh_Head;
					}

					break;
				}
				case MOUSEBUTTONS:
					{
						register WORD x,y;

						if (mouseX <= actualEditor->xoff)
							x = 0;
						else
							x = (mouseX - actualEditor->xoff)
								/ actualEditor->cw;
						if (++x >= actualEditor->wcw)
							x = actualEditor->wcw - 1;
						x += actualEditor->leftpos;
						if (x > MAXWIDTH)
							x = MAXWIDTH;

						if (mouseY <= actualEditor->yoff)
							y = 0;
						else
							y = (mouseY - actualEditor->yoff)
								/ actualEditor->ch;

						if ((y < actualEditor->wch)
							&& (actualEditor->zlinesptr[y]))
						{
							actualEditor->xpos = x;
							actualEditor->wdy  = y;
							actualEditor->ypos = actualEditor->zlinesnr[y];

							printXpos();
							printYpos();
						}
					}

				case NEWSIZE:
					initWindowSize(actualEditor);

					/* check if cursor still in window! */
					if (actualEditor->xpos > actualEditor->leftpos
														+actualEditor->wcw)
					{
						actualEditor->xpos = actualEditor->leftpos
													 + actualEditor->wcw;
						printXpos();
					}

					if (actualEditor->wdy >= actualEditor->wch)
					{
						actualEditor->ypos = actualEditor->zlinesnr
							[(actualEditor->wdy  = actualEditor->wch - 1)];
						printYpos();
					}

					break;

				case REFRESHWINDOW:
					BeginRefresh(actualEditor->window);
					printAll();
					EndRefresh(actualEditor->window,TRUE);
					break;

				case GADGETUP:
				{
					register UBYTE *ptr;
					register SHORT pos,hw;

					if (ptr = executeCommand(actualEditor->gc_SIBuffer))
						if (ptr == -1L)
							running = FALSE;
						else
						{
							if	(ptr >= 0x80000000)
								ptr =	NULL - ptr;

							/* set cursor in StringGadget to error */
							pos = ptr - actualEditor->gc_SIBuffer;
							actualEditor->gc_GadgetSI.BufferPos = pos;
							if (pos < actualEditor->gc_GadgetSI.DispCount)
								actualEditor->gc_GadgetSI.DispPos = 0;
							else
								actualEditor->gc_GadgetSI.DispPos = pos
										- actualEditor->gc_GadgetSI.DispCount / 2;

							/* Gagdet aktivated: */
							ActivateGadget(&(actualEditor->G_Command),
											  	actualEditor->window,NULL);
							DisplayBeep(NULL);
						}

					break;
				}

				case CLOSEWINDOW:
					running = FALSE;
					break;

				default:
					printf("Not a processable event: %lx\n",class);

			} /* of case */

			saveIfCursorMoved();
		} /* of while (GetMsg()) */
	} while (running);
	/*#ENDFD*/

Ende:
	/* Close all editor windows: */
	while (ed = RemHead(&editorList))
		CloseEditor(ed);

	/* Close UserPort: */
	if (edUserPort)
	{
		DeletePort(edUserPort);
		edUserPort = NULL;
	}

	/* Font closed: */
	if (infoFont)
	{
		CloseFont(infoFont);
		infoFont = NULL;
	}

	/* Close Libraries: */
	if (DosBase)
	{
		CloseLibrary(DosBase);
		DosBase = NULL;
	}
	if (GfxBase)
	{
		CloseLibrary(GfxBase);
		GfxBase = NULL;
	}
	if (IntuitionBase)
	{
		CloseLibrary(IntuitionBase);
		IntuitionBase = NULL;
	}
}
/*#ENDFD*/
