
/*
 * MAIN.C
 *
 *	(C)Copyright 1987 by Matthew Dillon, All Rights Reserved.
 *
 */

#include "defs.h"

Prototype int		  main		    (int, char **);
Prototype void		  do_tomouse	    (void);
Prototype void		  exiterr	    (char *);
Prototype int		  breakcheck	    (void);
Prototype void		  breakreset	    (void);
Prototype int		  ops		    (char **, int);

Prototype struct MsgPort * Sharedport;
Prototype char		   MShowTitle;
Prototype char		 * PubScreenName;
Prototype char		   noadj;
Prototype struct GfxBase * GfxBase;

typedef struct WBStartup    WBS;
typedef struct DiskObject   DISKOBJ;

static BOOL	 DoIconify;	    /* Should I iconify the new windows */
static BOOL	 NewDME;	    /* Should I create a new XDME ? */
static short	 Mx, My;	    /* Mouse-Coords */

struct MsgPort * Sharedport;	    /* Port for all Windows */
char		 MShowTitle;	    /* Should DME refresh the title ? */
char	       * PubScreenName;     /* Name of PublicScreen */
char		 noadj; 	    /* for blocking software adj. of prop gad
				       when intuition (user) already did it */

struct IntuitionBase * IntuitionBase;
struct GfxBase	     * GfxBase;
struct Library	     * IconBase;
struct Library	     * AslBase;
static char	     * Ffile;


int wbmain(WBS * wbs)
{
    return (main (0, (char **)wbs));
}


int main (int mac, char ** mav)
{
    char   nf;		    /* # files on command line	   */
    char   iawm        = 0; /* overide mouse buttons	   */
    char   dontwait    = 0; /* don't wait for a message    */
    short  i;		    /* temp. counter		   */
    short  Code;	    /* IDCMP->Code		   */
    ULONG  Qualifier;	    /* IDCMP->Qualifier 	   */
    PROC * proc        = (PROC *)FindTask(NULL);   /* our Task    */
    BPTR   origlock;	    /* Start-Lock		   */
    ULONG  wait_ret;	    /* HD Result of Wait	   */
    ULONG  Mask        = 0; /* Mask for Wait()             */
    char   gad_active  = 0; /* Is prop-gadget active ?	   */
    char   mmove       = 0; /* Mousemove		   */
    short  mqual;	    /* Qualifiers for mmove	   */

    /* Detach from CLI */
    fclose (stdin);
    /*fclose (stdout);*/    /*  assume person will run >nil: so all
				debugging output will still work. */
    fclose (stderr);        /*  close stderr & console ref. */
    origlock = CurrentDir (DupLock ((BPTR)proc->pr_CurrentDir));

    /* Init lists */
    NewList ((LIST *)&DBase);
    NewList ((LIST *)&PBase);

    IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library", 34L);
    GfxBase	  = (struct GfxBase       *)OpenLibrary ("graphics.library",  34L);
    if (!IntuitionBase || !GfxBase)
	exiterr ("cannot open intuition or graphics library");

    if (AslBase = OpenLibrary ("asl.library", 37L))
	FReq = AllocAslRequest (ASL_FileRequest, NULL);
    else if (ReqToolsBase = (struct ReqToolsBase *)OpenLibrary ("reqtools.library", 37))
	RFReq = rtAllocRequestA (RT_FILEREQ, NULL);
    else
	exiterr ("I need ASL- or ReqTools-Library");

    PageJump = 80;	    /* for Propgad & pageup/down */
    DoIconify = 0;

    String = NULL;	    /*	initialize scanf variable   */

    PubScreenName = NULL;	/* No screen yet, i.e. Workbench */

    ActualBlock.ep = NULL;	/* No block */

    if (mac == 0) {             /*  WORKBENCH STARTUP   */
	Wdisable = 0;		/*  allow icon save	*/
	Wbs = (WBS *)mav;

	if (!(IconBase = OpenLibrary ("icon.library", 0)) )
	    exiterr ("unable to open icon library");
    }

#ifdef AREXX
    /* Init AREXX */
    mountrequest (0);
    openrexx ();     /*   do this after the last possible call to exiterr() */
    mountrequest (1);
#endif

    /* Init KeyBoard */
    resethash ();

    /* WB-Startup or CLI ? */
    if (Wbs) {
	/* Work on TOOLTypes */
	if (Wbs->sm_ArgList[0].wa_Lock) {
	    DISKOBJ * Do;		  /* For WB-Startup */
	    BPTR      savelock = CurrentDir ((BPTR)Wbs->sm_ArgList[0].wa_Lock);

	    if (Do = GetDiskObject (Wbs->sm_ArgList[0].wa_Name)) {
		ops (Do->do_ToolTypes, 1);
		FreeDiskObject (Do);
	    }

	    CurrentDir (savelock);
	}

	mac = Wbs->sm_NumArgs;
	nf = mac - 1;
    } else {
	nf = ops (mav+1, 0);
    }

    {
	struct MsgPort * mp;
	char * buf;

	buf = malloc (1024);

	Forbid ();
	mp = FindPort ("XDME.1");
	Permit ();

	/* Do I have to open my own new window or can (must) I use an old DME */
	if (NewDME || !strcmp(RexxPortName, "XDME.1") || !mp)
	    NewDME = TRUE;
	else
	    NewDME = FALSE;

	/* Process all arguments */
	for (i = 1; i < mac; i ++) {
	    char    * str;
	    DISKOBJ * dso;

	    if (Wbs) {
		str = Wbs->sm_ArgList[i].wa_Name;

		UnLock (CurrentDir(DupLock((BPTR)Wbs->sm_ArgList[i].wa_Lock)));

		if (dso = GetDiskObject (Wbs->sm_ArgList[i].wa_Name)) {
		    ops (dso->do_ToolTypes, 1);
		    FreeDiskObject (dso);
		}
	    } else {
		str = mav[i];

		if (*str == '-') {   /* Don't process options */
		    if (str[1] == '-') /* Step over 2nd arg */
			i ++;

		    continue;
		}
	    }

	    /* Load project ? */
	    if (!stricmp (str, "XDME_Project_File")) {
		if (NewDME) {
		    if (!load_project ())
			nf --; /* Cannot load */
		} else {
		    strcpy (buf, "cd `");

		    if (getpathto (origlock, "", buf + 4)) {
			strcat (buf, "' projectload");

			do_rexx ("XDME.1", buf);
		    }
		}
	    } else {
		if (NewDME) {
		    /* Normal file. Open new window */
		    do_newwindow ();

		    /* Load file for editing */
		    av[0] = (ubyte *)"newfile";
		    av[1] = (ubyte *)str;
		    do_edit ();

		    /* Show title */
		    MForceTitle = 1;
		    window_title ();

		    if (DoIconify)
			do_iconify ();
		} else { /* Use AREXX */
		    strcpy (buf, "newwindow cd `");

		    if (getpathto (origlock, "", buf + 14)) {
			sprintf (buf + strlen (buf), "' newfile `%s'%s",
			    str, (DoIconify ? " iconify" : ""));
			do_rexx ("XDME.1", buf);
		    }
		}
	    } /* No PROJECTFILE */
	} /* For all args */

	if (nf == 0) {  /* no files to edit: Open simple empty window */
	    if (NewDME) {
		do_newwindow ();

		if (DoIconify)
		    do_iconify ();
	    } else {
		if (DoIconify) {
		    do_rexx ("XDME.1", "newwindow iconify");
		} else {
		    do_rexx ("XDME.1", "newwindow");
		}
	    }
	} /* No files */

	free (buf);
    } /* Block */

    if (!NewDME) /* All done, quit */
	goto quit_dme;

    /* Read main .edrc file */
    mountrequest (0);
    av[0] = "source";
    av[1] = (ubyte *)"s:.edrc";
    do_source (TRUE);   /* Display error */

    /* Read other file (if possible) */
    av[1] = (ubyte *)((Ffile) ? Ffile : ".edrc");
    do_source (FALSE); /* Not */
    mountrequest (1);

    /* Initialize certain fields in structure */
    {
	ED * ep;
	ED * eb = GetHead ((LIST *)&DBase);

	for (ep = eb; ep = GetSucc(&ep->Node); ) {
	    ep->Tabstop    = eb->Tabstop;
	    ep->Margin	   = eb->Margin;
	    ep->Insertmode = eb->Insertmode;
	    ep->IgnoreCase = eb->IgnoreCase;
	    ep->Wordwrap   = eb->Wordwrap;
	    ep->Autosplit  = eb->Autosplit;
	    ep->Autoindent = eb->Autoindent;
	    ep->AutoUnblock= eb->AutoUnblock;
	    ep->WWCol	   = eb->WWCol;
	    ep->FGPen	   = eb->FGPen;
	    ep->BGPen	   = eb->BGPen;
	    ep->HGPen	   = eb->HGPen;
	    ep->TPen	   = eb->TPen;

	    if (eb->Font) {
		ep->Font = eb->Font;
		eb->Font->tf_Accessors ++;
	    } /* if font */
	} /* for ed */
    }

    /* Get Wait()-Mask */
    Mask |= 1 << Sharedport->mp_SigBit;
    wait_ret = 0;

loop:
    if (!Ep->iconmode)  /* Display cursor ? */
	text_cursor(1);

    for (/*notdone = 1*/; !Quitflag /* && notdone */; ) {

	if (!Ep->iconmode)
	    window_title ();

	if (dontwait) {
	    dontwait --;
	} else {
	    wait_ret = Wait (Mask | RexxMask); /* HD für AREXX externes AREXX Command */
	}

	/*
	 *  NOTE: due to operation of breakcheck(), the userport signal
	 *  may not be set even if there are messages pending.
	 */
	if (wait_ret & RexxMask)          /* HD RexxMessage */
	{
	   text_cursor (0);

	   extern_rexx_command ();       /* process HD rexxcommand */

	   text_cursor (1);

	   /*if (Quitflag)
	       notdone=0; */
	}

	if (wait_ret&Mask)              /* HD IntuiMessage */
	{
	    IMESS * im;

	    while (im = (IMESS *)GetMsg(Ep->Win->UserPort)) {
		Msgchk	     = 1;
		Abortcommand = 0;
		Code	     = im->Code;
		Qualifier    = im->Qualifier;

		if (im->IDCMPWindow != Ep->Win) {
		    Overide = 0;

		    if (Comlinemode)
			escapecomlinemode ();

		    text_sync ();

		    MShowTitle = 0;

		    if (!Ep->iconmode)
			window_title ();

		    if (text_switch (im->IDCMPWindow) == 0) {
			ReplyMsg ((MSG *)im);
			continue;
		    }
		}

		Mx = im->MouseX;
		My = im->MouseY;

		switch(im->Class) {
		    case IDCMP_NEWSIZE: {
			struct Window * win = Ep->Win;
			short		wid;
			short		hei;

			/* Only works if uniconified */
			if (!Ep->iconmode) {
			    /* Leave Comlinemode if neccessary */
			    if (Comlinemode)
				escapecomlinemode ();

			    /* Set new window-parameters */
			    set_window_params ();

			    /* Erase if neccessary */
			    wid = win->Width - win->BorderRight - 1;
			    hei = win->Height - win->BorderBottom - 1;

			    SetAPen (win->RPort, Ep->BGPen);

			    if (wid > Xpixs) {
				RectFill (win->RPort, Xpixs+1, Ybase,
				    wid, hei);
			    }

			    if (hei > Ypixs) {
				RectFill (win->RPort, Xbase, Ypixs+1,
				    Xpixs, hei);
			    }

			    /* Update Text */
			    if (!text_sync ())
				text_redisplay ();

			    /* Show cursor */
			    text_cursor (1);
			}
		    break; } /* NEWSIZE */

		    case IDCMP_MOUSEBUTTONS:
			/* Avoid Crashing if Window is closed during keyctl() */
			ReplyMsg ((struct Message *)im);
			im = NULL;

			switch(Code) {
			    case MENUDOWN:
				/* Only uniconify */

				if (Ep->iconmode || iawm) {
				    uniconify ();
				    text_cursor (1);
				    break;
				}

				ReportMouse (TRUE, Ep->Win);

				text_cursor (0);
				keyctl (NULL, Code|0x80, Qualifier);
				text_cursor (1);
			    break;

			    case SELECTDOWN:
				ReportMouse (TRUE, Ep->Win);
				ModifyIDCMP (Ep->Win, Ep->Win->IDCMPFlags |
					IDCMP_INTUITICKS);

				text_cursor (0);
				keyctl (NULL, Code|0x80, Qualifier);
				text_cursor (1);
			    break;

			    case MIDDLEDOWN:
				do_clipins ();  /* insert text from clipboard */
				text_cursor (1);
			    break;

			    case SELECTUP:
				ReportMouse (FALSE, Ep->Win);
				ModifyIDCMP (Ep->Win, Ep->Win->IDCMPFlags &
					~IDCMP_INTUITICKS);
			    break;

			    case MENUUP:
				ReportMouse (FALSE, Ep->Win);
			    break;

			    case MIDDLEUP:
			    break;
			}
		    break; /* IDCMP_MOUSEBUTTONS */

		    case IDCMP_RAWKEY: {
			IMESS	       * im1;
			IMESS		 copy;
			struct MsgPort * up;

			/* Prevent crashing in do_iconify()->
			   closesharedwindow */

			memcpy (&copy, im, sizeof (IMESS));
			ReplyMsg ((struct Message *)im);
			im = NULL;

			/* Process Key-Down */
			if (!(Code & 0x80)) {
			    text_cursor (0);

			    keyctl (&copy, Code, Qualifier);

			    text_cursor (1);
			}

			/* Now discard all RAWKEY-Messages to avoid
			   run-after, i.e. stop immediately after key is
			   released */

			up = Ep->Win->UserPort;

			/* Discard all new KeyRepeat-Messages. Normal
			   KeyPress-Messages are not affected. */
			while (im1 = (IMESS *)GetHead (&up->mp_MsgList)) {
			    if ((im1->Class != RAWKEY) ||
			       (!(im1->Qualifier & IEQUALIFIER_REPEAT) ))
				   break;

			    im1 = (IMESS *)GetMsg (up);
			    ReplyMsg ((struct Message *)im1); /* HD casted */
			}

		    break; } /* IDCMP_RAWKEY */

		    case IDCMP_MENUPICK: {
			char * str = menu_cmd (im);

			ReplyMsg ((struct Message *)im);
			im = NULL;

			if (str) {
			    /* Generate a copy of the string */
			    str = strcpy (malloc(strlen(str)+1), str);

			    /* Cursor off */
			    text_cursor (0);

			    do_command (str);   /* Do command */
			    free (str);

			    /* Cursor on */
			    text_cursor (1);
			}
		    break; } /* IDCMP_MENUPICK */

		    case IDCMP_CLOSEWINDOW:
			if (Comlinemode)
			    escapecomlinemode ();

			text_sync ();
			/*notdone = 0;*/
			Quitflag = 1;
		    break; /* IDCMP_CLOSEWINDOW */

		    case IDCMP_ACTIVEWINDOW:
			if (!Ep->iconmode) {
			    iawm = 1;
			    text_cursor (1);
			}
		    break; /* IDCMP_ACTIVEWINDOW */

		    case IDCMP_MOUSEMOVE:
			if (gad_active) {
			    int newtop = new_top ();

			    if (newtop != Ep->Topline) {
				newtop -= Ep->Topline;

				text_cursor (0); /* Cursor off */

				Ep->Line    += newtop;
				Ep->Topline += newtop;

				text_load ();

				scroll_display (0, newtop, 0, Ep->Topline,
					MAXLINELEN, Ep->Topline + Rows);

				text_cursor (1);    /* Cursor on */
			    }
			} else {
			    /* Process these after all messages have been
			       processed */
			    mmove = 1;
			    mqual = Qualifier;
			}
		    break; /* IDCMP_MOUSEMOVE */

		    case IDCMP_GADGETDOWN:
			if (Comlinemode)
			    escapecomlinemode ();

			noadj = 1;		/* block software prop refresh */

			gad_active = TRUE;

			text_sync ();
		    break;

		    case IDCMP_GADGETUP: {
			int newtop = new_top ();

			if (newtop != Ep->Topline) { /* Make sure we don't miss a jump */
			    newtop -= Ep->Topline;

			    text_cursor (0); /* Cursor off */

			    Ep->Line	+= newtop;
			    Ep->Topline += newtop;

			    text_load ();

			    scroll_display (0, newtop, 0, Ep->Topline,
				    MAXLINELEN, Ep->Topline + Rows);

			    text_cursor (1);    /* Cursor on */
			}

			gad_active = FALSE;

			noadj = 0;		/* reallow software prop refresh */
		    break; }

		    case IDCMP_INTUITICKS:
			mmove = 1;
			mqual = Qualifier;
		    break; /* IDCMP_INTUITICKS */
		} /* switch (class) */

		if (im)
		    ReplyMsg ((MSG *)im);

		if (/*!notdone ||*/ Quitflag) {
		    dontwait = 2;
		    goto boom;

		} /* if (!notdone || Quitflag) */
	    } /* While IntuiMessage */
	} /* if (Wait & Mask) */

	iawm = 0;

	if (mmove) {
	    uniconify ();

	    mmove = 0;

	    text_cursor (0);
	    keyctl (NULL, QMOVE, mqual);
	    text_cursor (1);
	} /* if (mmove) */
    } /* for (notdone = 1; !Quitflag && notdone;) */

boom:
    text_sync ();

    /* Close window(s) */
    {
	WIN	      * win;
	struct Gadget * gadget;
	int		result;

	do {
	    if (Ep->Modified) {
		uniconify ();
		text_cursor (1);

		result = getyn ("XDME Warning",
			"The file `%s' has been modified.\n"
			"Do you want to save it first ?",
			"Yes|No|Cancel", Ep->Name);

		switch (result) {
		    case 0:
			Quitflag = 0;
			goto loop;
		    break;

		    case 1:
			if (!do_save ()) {
			    Quitflag = 0;
			    goto loop;
			}
		    break;
		}
	    }

	    win    = Ep->Win;
	    gadget = Ep->PropGad;

	    text_uninit ();
	    closesharedwindow (win);

	    if (gadget)
		FreeMem (gadget, sizeof (struct PropGadget));
	} while (QuitAll && Ep);
    }

    /* If we have another window left */
    if (Ep) {
	Quitflag = 0;

	if (!Ep->iconmode)
	    set_window_params ();

	text_load ();

	MShowTitle = 0;
	goto loop;
    }

quit_dme:
    /* Close Port */
    if (Sharedport) {
	DeletePort (Sharedport);
	Sharedport = NULL;
    }

#ifdef AREXX
    /* Close AREXX */
    closerexx ();
#endif

    /* Free Lock */
    UnLock (CurrentDir (origlock));

    /* Free memory */
    dealloc_hash ();
    check_stack (NULL);

#ifdef DEBUG_MEM_H
    _debug_FreeAllMem ();
#endif

    /* All OK. */
    exiterr (NULL);
} /* main */


void do_tomouse (void)
{
    short cx, cy;
    short minx, miny, maxx, maxy;

    if (Columns < 2 || Rows < 2)
	return;

    cx = (Mx-Xbase);
    if (cx >= 0) {
	if (cx < Xpixs)
	    cx /= Xsize;
	else
	    cx = Rows;
    } else
	cx = -1;

    cy = (My-Ybase);
    if (cy >= 0) {
	if (cy < Ypixs)
	    cy /= Ysize;
	else
	    cy = Columns;
    } else
	cy = -1;

    minx = 0;		    /* Scroll when MOUSE left window :-/ */
    miny = 0;
    maxx = Columns;
    maxy = Rows;

    if (cx < minx) { /* to the left */
	do_scrollleft ();

	if (cy < miny) { /* Also up */
	    do_scrollup ();
	} else if (cy >= maxy) { /* also down */
	    do_scrolldown ();
	}
    } else if (cx >= maxx) { /* dito to the right */
	do_scrollright ();

	if (cy < miny) {
	    do_scrollup ();
	} else if (cy >= maxy) {
	    do_scrolldown ();
	}
    } else { /* x is ok, check y */
	if (cy < miny) { /* up */
	    do_scrollup ();
	} else if (cy >= maxy) { /* down */
	    do_scrolldown ();
	} else
	    text_position (cx, cy); /* Just reposition cursor */
    }
} /* do_tomouse */


void exiterr (char * str)
{
    if (str) {
	if (Output ()) {
	    Write (Output (), str, strlen (str));
	    Write (Output (), "\n", 1);
	} else {
	    error (str);
	}
    }

    if (IconBase)      {
	CloseLibrary (IconBase);
	IconBase = NULL;
    }

    if (ReqToolsBase)  {
	if (RFReq)
	    rtFreeRequest (RFReq);

	CloseLibrary ((struct Library *)ReqToolsBase);
	ReqToolsBase = NULL;
    }

    if (AslBase) {
	if (FReq)
	    FreeAslRequest (FReq);

	CloseLibrary (AslBase);
	AslBase = NULL;
    }

    if (GfxBase) {
	CloseLibrary ((struct Library *)GfxBase);
	GfxBase = NULL;
    }

    if (IntuitionBase) {
	CloseLibrary ((struct Library *)IntuitionBase);
	IntuitionBase = NULL;
    }

    if (str)
	exit (1);

    exit (0);
}


/*
 *  Check break by scanning pending messages in the I stream for a ^C.
 *  Msgchk forces a check, else the check is only made if the signal is
 *  set in the I stream (the signal is reset).
 */

int breakcheck (void)
{
    IMESS	* im;
    WIN 	* win  = Ep->Win;
    struct List * list = &win->UserPort->mp_MsgList;

    if (Msgchk || (SetSignal (0,0) & (1<<win->UserPort->mp_SigBit))) {
	Msgchk = 0;
	SetSignal (0,1<<win->UserPort->mp_SigBit);

	im = (IMESS *)list->lh_Head;
	Forbid();

	for ( ; im != (IMESS *)&list->lh_Tail;
		im = (IMESS *)im->ExecMessage.mn_Node.ln_Succ) {
	    if (im->Class == RAWKEY && (im->Qualifier & 0xFB) == 0x08 &&
		im->Code == CtlC) {

		Permit ();
		SetSignal (SIGBREAKF_CTRL_C,SIGBREAKF_CTRL_C);
		return (1);
	    }
	} /* for IMESS */

	Permit ();
    }

    return (0);
} /* breakcheck */


void breakreset (void)
{
    SetSignal(0, SIGBREAKF_CTRL_C);
}


int ops (char ** av, int iswb)
{
    short  nonops;	/* Number of non-options */
    short  i;		/* Counter */
    char * str; 	/* Actual argument */

    for (i = nonops = 0; str = av[i]; i ++) {
	if (iswb) {
	    if (strncmp (str, "ARG", 3) == 0) {
		while (*str && *str != '-')
		    ++str;
	    }
	}

	if (*str == '-') {
	    switch (str[1]) {
		case 'f':
		    if (!str[2]) {
			if (!(Ffile = av[++ i]) ) {
			    exiterr ("XDME: -f needs an argument");
			}

			str[1] = '-';
		    } else
			Ffile = str+2;
		break;

		case 'p':
		    if (str[2] == 's') {
			if (!str[3]) {
			    if (!(PubScreenName = av[++ i]) ) {
				exiterr ("XDME: -ps needs an argument");
			    }

			    str[1] = '-';
			} else
			    PubScreenName = str+3;
		    }
		break;

#ifdef AREXX
		case 'n':
		    NewDME = 1;
		break;
#endif

		case 'i':
		    DoIconify = 1;
		break;
	    }
	} else {
	    nonops ++;
	}
    }

    return ((int)nonops);
} /* ops */


