/*
 *    $VER:Snap.c - (10.09.95) 12:15:52 Copyright © 1995 by Mikael Karlsson & Sylvain ROUGIER
 *
 *      Created: 1988
 *      Modified:	10 Sep 1995	12:15:52
 *
 *      Make>> smake
 *
 * 04/06/95:
 *		Try to compile originale Snap 1.61 src
 *    Bumped to 1.99
 * 04/06/95:
 *		Bumped to 2.00
 *		try to fix bug occuring when cliping gfx on >6 depth screen
 *	10/09/95:
 *		the SwapColor seem not work under CyberGFX V40.?, this is not true, it seems to be a bug of CyberGFX.
 */

/***********************************************\
*                                               *
*                     Snap                      *
*         © Mikael Karlsson 1988-1991           *
*                                               *
\***********************************************/
/* Auto: make "CCEXTRA=-wq -qf"
 */

#include <stdio.h>

#include "Snap.h"

#include "proto/Misc.h"
#include "proto/GfxSnap.h"

#ifdef SNAPREXX
#include "minrexx.h"
#include "proto/MinRexx.h"
#endif	/* SNAPREXX */

#define ARGVAL( ) ( ( *argv && *++( *argv)) || ( --argc && *++argv))

char Version[ ] = "$VER: 2.00 © 1991 Mikael Karlsson,Absolut Software & Sylvain ROUGIER\n";

BOOL Kick36;

/* signals */
LONGBITS startsignal, insertsignal, cancelsignal;
LONGBITS donesignal, movesignal, clicksignal;
LONGBITS timersignal, initsignal, cwsignal, ticksignal;
ULONG startsignum = -1L;
ULONG insertsignum = -1L;
ULONG cancelsignum = -1L;
ULONG donesignum = -1L;
ULONG movesignum = -1L;
ULONG clicksignum = -1L;
ULONG initsignum = -1L;
ULONG cwsignum = -1L;
ULONG ticksignum = -1L;
ULONG WaitSignal;

/* program */
struct SnapRsrc *SnapRsrc = NULL;
struct Task *MyTask;

/* Snap state machine */
WORD action;
WORD state;

/* clipboard */
struct IOClipReq *ClipReq = NULL;
struct MsgPort *ClipPort = NULL;

/* timer device */
struct MsgPort *TimerPort = NULL;
struct timerequest MyTR;

/* input device */
struct MsgPort *inputDevPort = NULL;
struct Interrupt handlerStuff;
struct IOStdReq *inputRequestBlock = NULL;
struct InputEvent SimEvent;
WORD textqual;
WORD gfxqual;
WORD insertkey;
WORD cwkey;
WORD modinsert;

UBYTE *CharData = NULL;
UBYTE TrueUnderscore;

/* console */
struct MsgPort *ConPort = NULL;
struct IOStdReq *ConIOR = NULL;
struct KeyMap keymap;

/* windows */
#ifdef SNAPGFX
struct MsgPort *Sharedport = NULL;
SHORT Sharedrefs;
IMPORT struct Window *ControlWindow;
struct Window *SaveWin = NULL;
IMPORT struct Gadget SaveGad;
IMPORT struct Gadget NameGad;
IMPORT struct StringInfo TranspSI;
IMPORT struct Image ActiveDiskImage;
IMPORT struct Image InactiveDiskImage;
IMPORT struct Image ActiveClipImage;
IMPORT struct Image InactiveClipImage;

#endif	/* SNAPGFX */
IMPORT UBYTE *WindowTitle;

/* libraries */
IMPORT struct ExecBase *SysBase;
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Library *LayersBase = NULL;
struct Library *DiskfontBase = NULL;
struct Library *IconBase = NULL;

#ifdef SNAPGFX
#ifdef REQLIB
struct ReqBase *ReqBase = NULL;

#endif	/* REQLIB */
#ifdef ASLLIB
struct Library *AslBase = NULL;

#endif	/* ASLLIB */
#endif	/* SNAPGFX */

/* graphics */
struct Screen *theScreen;
struct RastPort rp, TempRp, MyRP;
struct BitMap TempBM, MyBM;
UBYTE *TempRaster = NULL;

#ifdef SNAPGFX
#ifdef REQLIB
struct ReqFileRequester *NameFR = NULL;

#endif	/* REQLIB */
#ifdef ASLLIB
struct FileRequester *AslNameFR = NULL;

#endif	/* ASLLIB */
char SaveName[ DSIZE + FCHARS + 2];
BPTR SnapFile;

#endif	/* SNAPGFX */

/* ARexx stuff */
#ifdef SNAPREXX
ULONG rexxsignal;
IMPORT struct rexxCommandList rcl[ ];
//WORD disp( );

#endif	/* SNAPREXX */

#ifdef AZTEC_C
int stricmp( char *s1, char *s2)
{
	char c1, c2;

	while ( *s1 && *s2)
	{
		if ( ( c1 = *( s1++)) >= 'a' && c1 <= 'z')
		{
			c1 -= 32;
		}
		if ( ( c2 = *( s2++)) >= 'a' && c2 <= 'z')
		{
			c2 -= 32;
		}

		if ( c1 != c2)
		{
			return ( c1 - c2);
		}
	}

	return ( *s1 - *s2);
}


int strnicmp( char *s1, char *s2, int n)
{
	char c1, c2;

	while ( *s1 && *s2 && --n > 0)
	{
		c1 = *( s1++);
		c2 = *( s2++);

		if ( c1 >= 'a' && c1 <= 'z')
		{
			c1 -= 32;
		}
		if ( c2 >= 'a' && c2 <= 'z')
		{
			c2 -= 32;
		}

		if ( c1 != c2)
		{
			return ( c1 - c2);
		}
	}

	c1 = *s1;
	c2 = *s2;

	if ( c1 >= 'a' && c1 <= 'z')
	{
		c1 -= 32;
	}
	if ( c2 >= 'a' && c2 <= 'z')
	{
		c2 -= 32;
	}

	return ( c1 - c2);
}
#endif

LONG dectoint( REGISTER char *str)
{
	REGISTER long val = 0;
	REGISTER char c;

	while ( ( c = *str) >= '0' && c <= '9')
	{
		val = ( ( ( val << 2) + val) << 1) + c - '0';
		str++;
	}
	return ( val);
}

LONG HexToInt(  char *str)
{
	REGISTER long val = 0;
	REGISTER char c;

	if ( !strnicmp( str, "0x", 2))
	{
		str += 2;
	}
	while ( c = *str)
	{
		val <<= 4;
		val |= ( c & 15) + ( ( c >= '0' && c <= '9') ? 0 : 9);
		str++;
	}
	return val;
}

WORD insertcount;

VOID InsertAscii( ULONG ascii)
{
	if ( insertcount == 1)
	{			/* Time for second char */
		/* Not necessary to patch here but it guarantees
		   that all inserted chars end up in the same window. */
		SafePatch( );
	}
	if ( AsciiToInputEvent( ascii, &SimEvent, &keymap))
	{
		DoIO( ( struct IORequest *)inputRequestBlock);
		if ( SnapRsrc->chardelay)
		{
			MyTR.tr_node.io_Command = TR_ADDREQUEST;
			MyTR.tr_time.tv_micro = SnapRsrc->chardelay;
			MyTR.tr_time.tv_secs = 0;
			DoIO( ( struct IORequest *)&MyTR);
		}
	}
	++insertcount;
}

#ifdef SNAPGFX
VOID GadText( struct Gadget *Gad, char *Str, LONG Len)
{
	char temp[ 256];
	SHORT i;

	SetDrMd( ControlWindow->RPort, JAM2);
	SetAPen( ControlWindow->RPort, 0L);
	RectFill( ControlWindow->RPort, ( LONG) Gad->LeftEdge, ( LONG) Gad->TopEdge,
		 ( LONG) Gad->LeftEdge + Gad->Width - 1, ( LONG) Gad->TopEdge + Gad->Height - 1);
	SetAPen( ControlWindow->RPort, 1L);
	SetBPen( ControlWindow->RPort, 0L);
	Move( ControlWindow->RPort,
	     ( LONG) Gad->LeftEdge + 1,
	 ( LONG) Gad->TopEdge + ControlWindow->RPort->Font->tf_Baseline + 1);
	if ( TextLength( ControlWindow->RPort, Str, Len) > Gad->Width)
	{
		i = Len;
		strncpy( temp, Str, i - 3);
		strcat( temp, "...");
		while ( TextLength( ControlWindow->RPort, temp, ( LONG) i) > Gad->Width)
		{
			--i;
			temp[ i] = '\0';
			temp[ i - 3] = '.';
		}
		Text( ControlWindow->RPort, temp, ( LONG) i);
	}
	else
	{
		Text( ControlWindow->RPort, Str, Len);
	}
}


VOID SwapColorMap( struct GfxSnap *GS)
{
	struct ViewPort *vp = &GS->window->WScreen->ViewPort;
	LONG i = ( GS->viewmode & HAM ? 16 : 1L << GS->depth);
	ULONG col;

	if ( SysBase->LibNode.lib_Version < 39)
	{
		while ( i-- && ( col = GetRGB4( vp->ColorMap, i)) != -1L)
		{
			SetRGB4( vp, i,
				( LONG) GS->rgb[ i][ 0] >> 4,
				( LONG) GS->rgb[ i][ 1] >> 4,
				( LONG) GS->rgb[ i][ 2] >> 4);
			GS->rgb[ i][ 0] = RGB4ToRR( col);
			GS->rgb[ i][ 1] = RGB4ToGG( col);
			GS->rgb[ i][ 2] = RGB4ToBB( col);
		}
	}
	else
	{
		while ( i--)
		{
			ULONG RGB[ 3];

			GetRGB32( vp->ColorMap, i, 1, RGB);
			SetRGB32CM( vp->ColorMap, i, RGB8ToRGB32( GS->rgb[ i][ 0]), RGB8ToRGB32( GS->rgb[ i][ 1]), RGB8ToRGB32( GS->rgb[ i][ 2]));
			GS->rgb[ i][ 0] = RGB32ToRGB8( RGB[ 0]);
			GS->rgb[ i][ 1] = RGB32ToRGB8( RGB[ 1]);
			GS->rgb[ i][ 2] = RGB32ToRGB8( RGB[ 2]);
		}
	}
}

VOID CheckWindowMsgs( )
{
	struct IntuiMessage *Msg;
	struct IntuiMessage *QdMsg = NULL;
	ULONG im_Class;
	USHORT Code;
	struct Window *Win;
	struct Gadget *Gad;
	struct GfxSnap *SwapGS = NULL;

	while ( Sharedport &&
		( QdMsg || ( Msg = ( struct IntuiMessage *)GetMsg( Sharedport))))
	{
		if ( QdMsg)
		{
			Msg = QdMsg;
			QdMsg = NULL;
		}
		im_Class = Msg->Class;
		Code = Msg->Code;
		Win = Msg->IDCMPWindow;
		Gad = ( struct Gadget *)Msg->IAddress;
		ReplyMsg( ( struct Message *)Msg);
		switch ( im_Class)
		{
		case CLOSEWINDOW:
			{
				struct GfxSnap *GS = NULL;

				if ( Win == ControlWindow)
				{
					ControlWindow = NULL;
					if ( SaveWin)
					{
						SetWindowTitles( SaveWin, ( char *)WindowTitle, ( char *)-1);
						SaveWin = NULL;
					}
				}
				else
				{
					GS = ( struct GfxSnap *)Win->UserData;
					Snp_FreeBitMap( GS->BitMap, GS->width, GS->height);
					GS->BitMap = NULL;

					if ( Win == SaveWin || Sharedrefs == 1)
					{
						if ( ControlWindow)
						{
							OffGadget( &SaveGad, ControlWindow, NULL);
						}
						SaveWin = NULL;
					}
				}
				closesharedwindow( Win);
				DeleteGfxSnap( GS);
				break;
			}
		case NEWSIZE:
			{
				AdjustSize( ( struct GfxSnap *)Win->UserData);
				break;
			}
		case MOUSEMOVE:
			{
				/* Collapse all consecutively queued MOUSEMOVE msgs */
				while ( ( QdMsg = ( struct IntuiMessage *)GetMsg( Sharedport))
				       && ( QdMsg->Class == MOUSEMOVE))
				{
					ReplyMsg( ( struct Message *)QdMsg);
				}
				SyncGS( ( struct GfxSnap *)Win->UserData);
				break;
			}
		case REFRESHWINDOW:
			{
				BeginRefresh( Win);
				SyncGS( ( struct GfxSnap *)Win->UserData);
				EndRefresh( Win, 1L);
			}
		case INACTIVEWINDOW:
			{
				if ( Win != ControlWindow)
				{
					struct GfxSnap *GS;

					GS = ( struct GfxSnap *)Win->UserData;
					if ( SwapGS)
					{
						SwapColorMap( SwapGS);
						SwapGS = NULL;
					}
					GS->DiskGad.GadgetRender = ( APTR) & InactiveDiskImage;
					GS->ClipGad.GadgetRender = ( APTR) & InactiveClipImage;
					RefreshGList( &GS->DiskGad, GS->window, NULL, -1);
				}
				break;
			}
		case ACTIVEWINDOW:
			{
				if ( Win != ControlWindow)
				{
					struct GfxSnap *GS;

					GS = ( struct GfxSnap *)Win->UserData;
					GS->DiskGad.GadgetRender = ( APTR) & ActiveDiskImage;
					GS->ClipGad.GadgetRender = ( APTR) & ActiveClipImage;
					RefreshGList( &GS->DiskGad, GS->window, NULL, -1);
				}
				break;
			}
		case GADGETUP:
			{
				switch ( Gad->GadgetID)
				{
				case VPROP:
				case HPROP:
					{
						SyncGS( ( struct GfxSnap *)Win->UserData);
						break;
					}
				case SAVEGAD:
					{
					      savepic:
						if ( SaveWin)
						{
							WORD success = 0;
							struct GfxSnap *GS;

							GS = ( struct GfxSnap *)SaveWin->UserData;

							if ( SaveName[ 0] == '\0')
							{
								DisplayBeep( NULL);
								ActivateGadget( &NameGad, ControlWindow, NULL);
								break;
							}
							SnapFile = ( BPTR) Open( ( char *)SaveName, MODE_NEWFILE);
							if ( SnapFile)
							{
								struct CBFHandle CBFH;

								CBFH.Type = CBFFILE;
								CBFH.Handle.File = SnapFile;
								success = SaveGS( GS, &CBFH);
								Close( SnapFile);
							}
							if ( success)
							{
								SetWindowTitles( ControlWindow, "Saved ok", ( char *)-1);
							}
							else
							{
								DeleteFile( ( char *)SaveName);
								DisplayBeep( NULL);
								SetWindowTitles( ControlWindow, "Save failed", ( char *)-1);
							}
						}
						break;
					}
				case NAMEGAD:
					{	/* Should only happen with Req */
#ifdef ASLLIB
						if ( ( AslNameFR) && ( Kick36))
						{
							if ( RequestFile( AslNameFR))
							{
								strncpy( SaveName, AslNameFR->rf_Dir, sizeof ( SaveName));
								AddPart( ( UBYTE *) SaveName,
									( UBYTE *) AslNameFR->rf_File,
									sizeof ( SaveName));
							}
							GadText( &NameGad, SaveName, ( LONG) strlen( SaveName));
						}
#else
						if ( 0)
						{
						}
#endif	/* ASLLIB */
#ifdef REQLIB
						else if ( NameFR)
						{
							NameFR->Title = "Save picture as...";
							NameFR->PathName = SaveName;
							NameFR->Window = ControlWindow;
							( VOID) BruceFileRequester( NameFR);
							GadText( &NameGad, SaveName, ( LONG) strlen( SaveName));
						}
#endif	/* REQLIB */
						break;
					}
				case DISKGAD:
					{
						struct GfxSnap *GS;

						if ( !ControlWindow && !OpenCW( ))
						{
							DisplayBeep( NULL);
							break;
						}
						if ( Win == SaveWin)
						{
							goto savepic;
						}
						if ( SaveWin)
						{
							SetWindowTitles( SaveWin, ( char *)WindowTitle, ( char *)-1);
							GS = ( struct GfxSnap *)SaveWin->UserData;
							RefreshGList( &GS->DiskGad, GS->window, NULL, 1L);
						}
						else
						{
							GadText( &SaveGad, "Save", 4L);
							OnGadget( &SaveGad, ControlWindow, NULL);
						}
						SaveWin = Win;
						SetWindowTitles( SaveWin, "Selected", ( char *)-1);
						GS = ( struct GfxSnap *)SaveWin->UserData;
						RefreshGList( &GS->DiskGad, GS->window, NULL, 1L);
						break;
					}
				case CLIPGAD:
					{
						struct CBFHandle CBFH;
						struct GfxSnap *GS = ( struct GfxSnap *)Win->UserData;

						CBFH.Type = CBFCLIP;
						CBFH.Handle.ClipReq = ClipReq;
						if ( !SaveGS( GS, &CBFH))
						{
							DisplayBeep( NULL);
						}
						break;
					}
				default:
					{
						break;
					}
				}
				break;
			}
		case MOUSEBUTTONS:
			{
				if ( Win != ControlWindow)
				{
					if ( Code == SELECTDOWN && !SwapGS)
					{
						SwapGS = ( struct GfxSnap *)Win->UserData;
						SwapColorMap( SwapGS);
					}
					else if ( Code == SELECTUP && SwapGS)
					{
						SwapColorMap( SwapGS);
						SwapGS = NULL;
					}
				}
				break;
			}
		default:
			{
				break;
			}
		}
	}
	if ( QdMsg)
	{
		ReplyMsg( ( struct Message *)QdMsg);
	}
}
#endif	/* SNAPGFX */

#define SnapWriteStr( str) fputs( str, stdout)
#define SnapWriteChar( char) fputc( char, stdout)

struct QualPair
{
	char *str;
	WORD val;
};

struct QualPair Qualifiers[ ] =
{
	{"LSHIFT", IEQUALIFIER_LSHIFT},
	{"RSHIFT", IEQUALIFIER_RSHIFT},
	{"CONTROL", IEQUALIFIER_CONTROL},
	{"LALT", IEQUALIFIER_LALT},
	{"RALT", IEQUALIFIER_RALT},
	{"LCOMMAND", IEQUALIFIER_LCOMMAND},
	{"RCOMMAND", IEQUALIFIER_RCOMMAND},
	{"MIDBUTTON", IEQUALIFIER_MIDBUTTON}
};

WORD ParseQual( char *quals)
{
	char *temp;
	WORD i;
	char oldc;
	WORD qual = 0;

	if ( ( '0' >= *quals) && ( *quals <= '9'))
	{
		return ( WORD)HexToInt(  quals);
	}

	while ( *quals)
	{
		temp = quals;
		while ( ( oldc = *quals) && oldc != '+')
		{
			quals++;
		}
		*quals = 0;
		for ( i = 0; i < ( sizeof ( Qualifiers) / sizeof ( Qualifiers[ 0])); i++)
		{
			if ( !stricmp( temp, Qualifiers[ i].str))
			{
				qual |= Qualifiers[ i].val;
				break;
			}
		}
		if ( *quals = oldc)
		{
			quals++;
		}
	}
	return qual;
}

WORD SetAltFont( char *str)
{
	struct TextAttr ta;
	struct TextFont *NewFont;
	char temp[ 33];
	WORD pos = 0;

	if ( strlen( str) <= 32)
	{

		strcpy( temp, str);
		ta.ta_Name = ( UBYTE *) temp;
		while ( temp[ pos] != '\0' && temp[ pos] != '/')
		{
			++pos;
		}
		if ( temp[ pos] == '\0')
		{		/* No size */
			ta.ta_YSize = 8;
		}
		else
		{
			temp[ pos] = '\0';
			ta.ta_YSize = dectoint( &temp[ pos + 1]);
		}
		if ( pos > 5)
		{
			if ( stricmp( &temp[ pos - 5], ".font"))
			{
				strcpy( &temp[ pos], ".font");
			}
		}
		else
		{
			strcpy( &temp[ pos], ".font");
		}
		ta.ta_Style = 0;
		ta.ta_Flags = 0;
		NewFont = SmartOpenFont( &ta);
		if ( NewFont)
		{
			if ( SnapRsrc->AlternateFont)
			{
				CacheSync( SnapRsrc->AlternateFont);
				CloseFont( SnapRsrc->AlternateFont);
			}
			SnapRsrc->AlternateFont = NewFont;
		}
	}
	return ( WORD)( NewFont ? 1 : 0);
}

struct SnapRsrc DefaultRsrc =
{
	{NULL, NULL, NT_RESOURCE, 0, SNAPRSRC},		/* Node */
	NULL,			/* Task */
	52,			/* Priority */
	IEQUALIFIER_RCOMMAND,	/* Graphics qualifier */
	IEQUALIFIER_LCOMMAND,	/* Text qualifier */
	0x17,			/* Insert key */
	0x11,			/* Control Window key */
	{'>', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/* Prepend */
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},	/* Append */
	TRUEUNDERSCORE,		/* Flags */
	0,			/* Char delay */
	0,			/* Line delay */
	0x7777,			/* Crawl pattern */
	UNIT_FRAME,		/* Starting unit */
	1,			/* Frame mask */
	'?',			/* Bad char */
	10,			/* Cache size */
	1,			/* Extra line spacing */
	{NULL, NULL, NULL},	/* MinList, Cached windows */
	NULL			/* Alternate font */
};

#ifdef LATTICE
VOID main( int argc, char **argv)
#else
WORD main( int argc, char **argv)
#endif
{
	WORD create = 0, usage = 0;

#ifdef AZTEC_C
	Enable_Abort = 0;
#endif	/* AZTEC_C */

	Kick36 = ( SysBase->LibNode.lib_Version >= 36 ? 1 : 0);

	if ( !( SnapRsrc = ( struct SnapRsrc *)OpenResource( SNAPRSRC)))
	{
		create = 1;
		SnapRsrc = Create( SnapRsrc);
		CopyMem( ( char *)&DefaultRsrc, ( char *)SnapRsrc, sizeof ( struct SnapRsrc));

		SnapRsrc->Task = FindTask( NULL);
		NewList( ( struct List *)&SnapRsrc->CachedWindows);
		AddResource( ( struct MiscResource *)SnapRsrc);
	}

	/* Open libraries since we might need them when parsing arguments */
	if ( !OpenLibs( ))
	{
		goto exitpoint;
	}

	if ( !argc)
	{			/* WB Startup */
		if ( !create)
		{		/* Second time from WB -- Remove Snap */
			Signal( SnapRsrc->Task, SIGBREAKF_CTRL_C);
			goto exitpoint;
		}
		else if ( IconBase)
		{		/* Is it possible to be started from Workbench
				   without icon.library being available. */
			BPTR olddir;
			struct WBStartup *wbstartup;
			struct DiskObject *diskobject;
			char *val;

			wbstartup = ( struct WBStartup *)argv;
			olddir = CurrentDir( wbstartup->sm_ArgList[ 0].wa_Lock);
			diskobject = GetDiskObject( wbstartup->sm_ArgList[ 0].wa_Name);
			if ( !diskobject)
			{
				goto skipargs;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "PRIORITY"))
			{
				WORD pri = dectoint( val);

				if ( pri > 50 && pri < 128)
				{
					SnapRsrc->Priority = pri;
				}
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "TEXTQUAL"))
			{
				if ( !( SnapRsrc->textqual = ParseQual( val)))
				{
					SnapRsrc->textqual = IEQUALIFIER_LCOMMAND;
				}
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "GFXQUAL"))
			{
				if ( !( SnapRsrc->gfxqual = ParseQual( val)))
				{
					SnapRsrc->gfxqual = IEQUALIFIER_RCOMMAND;
				}
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "INSERTKEY"))
			{
				SnapRsrc->insertkey = HexToInt( val);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "CWKEY"))
			{
				SnapRsrc->cwkey = HexToInt( val);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "APPEND"))
			{
				strncpy( &SnapRsrc->Append[ 0], val, 16);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "PREPEND"))
			{
				strncpy( &SnapRsrc->Prepend[ 0], val, 16);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "CHARDELAY"))
			{
				SnapRsrc->chardelay = dectoint( val);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "LINEDELAY"))
			{
				SnapRsrc->linedelay = dectoint( val) * 1000;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "CRAWLPTRN"))
			{
				SnapRsrc->CrawlPtrn = HexToInt( val);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "XEROX"))
			{
				SnapRsrc->flags |= XEROX;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "NOXEROX"))
			{
				SnapRsrc->flags &= ~XEROX;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "EARLYPATCH"))
			{
				SnapRsrc->flags |= EARLYPATCH;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "NOEARLYPATCH"))
			{
				SnapRsrc->flags &= ~EARLYPATCH;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "STARTUNIT"))
			{
				if ( *val == '1')
				{
					SnapRsrc->StartUnit = UNIT_CHAR;
				}
				else
				{
					SnapRsrc->StartUnit = UNIT_FRAME;
				}
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "TRUEUNDERSCORE"))
			{
				SnapRsrc->flags |= TRUEUNDERSCORE;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "FAKEUNDERSCORE"))
			{
				SnapRsrc->flags &= ~TRUEUNDERSCORE;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "JOINLONG"))
			{
				SnapRsrc->flags |= JOINLONG;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "NOJOINLONG"))
			{
				SnapRsrc->flags &= ~JOINLONG;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "SIMPLEREFRESH"))
			{
				SnapRsrc->flags |= SIMPLEREFRESH;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "SMARTREFRESH"))
			{
				SnapRsrc->flags &= ~SIMPLEREFRESH;
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "PLANEMASK"))
			{
				SnapRsrc->FrameMask = HexToInt( val);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "CACHESIZE"))
			{
				SnapRsrc->CacheSize = dectoint( val);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "LEADING"))
			{
				SnapRsrc->Leading = dectoint( val);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "BADCHAR"))
			{
				SnapRsrc->BadChar = ( *val ? *val : 0);
			}
			if ( val = FindToolType( diskobject->do_ToolTypes, "ALTFONT"))
			{
				SetAltFont( val);
			}
			FreeDiskObject( diskobject);
			goto skipargs;
		}
	}

	if ( create)
	{
		SnapWriteStr( "Snap");
		SnapWriteStr( &Version[ 5]);
	}

	for ( argc--, argv++; argc > 0; argc--, argv++)
	{
		if ( **argv == '-')
		{		/* Argument coming up */
			switch ( *++( *argv))
			{
			case 'p':
			      priority:{
					/* Priority */
					if ( ARGVAL( ))
					{
						WORD pri = dectoint( *argv);

						if ( pri > 50 && pri < 128)
						{
							SnapRsrc->Priority = pri;
						}
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 't':
			      textqual:{
					if ( ARGVAL( ))
					{
						if ( !( SnapRsrc->textqual = ParseQual( *argv)))
						{
							SnapRsrc->textqual = IEQUALIFIER_LCOMMAND;
						}
					}
					else
					{
						usage = 1;
					}
					break;
				}
#ifdef SNAPGFX
			case 'g':
			      gfxqual:{
					if ( ARGVAL( ))
					{
						if ( !( SnapRsrc->gfxqual = ParseQual( *argv)))
						{
							SnapRsrc->gfxqual = IEQUALIFIER_RCOMMAND;
						}
					}
					else
					{
						usage = 1;
					}
					break;
				}
#endif	/* SNAPGFX */
			case 'i':
			      insertkey:{
					if ( ARGVAL( ))
					{
						SnapRsrc->insertkey = HexToInt( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
#ifdef SNAPGFX
			case 'w':
			      cwkey:{
					if ( ARGVAL( ))
					{
						SnapRsrc->cwkey = HexToInt( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
#endif	/* SNAPGFX */
			case 'c':
			      chardelay:{
					if ( ARGVAL( ))
					{
						SnapRsrc->chardelay = dectoint( *argv) * 1000;
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'l':
			      linedelay:{
					if ( ARGVAL( ))
					{
						SnapRsrc->linedelay = dectoint( *argv) * 1000;
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'a':
			      crawlptrn:{
					if ( ARGVAL( ))
					{
						SnapRsrc->CrawlPtrn = HexToInt( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'X':
			      noxerox:{
					SnapRsrc->flags &= ~XEROX;
					break;
				}
			case 'x':
			      xerox:{
					SnapRsrc->flags |= XEROX;
					break;
				}
			case 'E':
			      noearlypatch:{
					SnapRsrc->flags &= ~EARLYPATCH;
					break;
				}
			case 'e':
			      earlypatch:{
					SnapRsrc->flags |= EARLYPATCH;
					break;
				}
			case 'R':
			      fakeunderscore:{
					SnapRsrc->flags &= ~TRUEUNDERSCORE;
					break;
				}
			case 'r':
			      realunderscore:{
					SnapRsrc->flags |= TRUEUNDERSCORE;
					break;
				}
			case 'J':
			      nojoinlong:{
					SnapRsrc->flags &= ~JOINLONG;
					break;
				}
			case 'j':
			      joinlong:{
					SnapRsrc->flags |= JOINLONG;
					break;
				}
			case 'A':
			      append:{
					char *dest = &SnapRsrc->Append[ 0];

					if ( ( *argv && *++( *argv)) || ( --argc && ++argv))
					{	/* "" is ok */
						char *src = *argv;
						WORD i = 16;

						while ( *src && i--)
						{
							*dest++ = *src++;
						}
						*dest = '\0';
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'P':
			      prepend:{
					char *dest = &SnapRsrc->Prepend[ 0];

					if ( ( *argv && *++( *argv)) || ( --argc && ++argv))
					{	/* "" is ok */
						char *src = *argv;
						WORD i = 16;

						while ( *src && i--)
						{
							*dest++ = *src++;
						}
						*dest = '\0';
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'u':
			      startunit:{
					if ( ARGVAL( ))
					{
						if ( **argv == '1')
						{
							SnapRsrc->StartUnit = UNIT_CHAR;
						}
						else
						{
							SnapRsrc->StartUnit = UNIT_FRAME;
						}
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'b':
			      planemask:{
					if ( ARGVAL( ))
					{
						SnapRsrc->FrameMask = HexToInt( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
#ifdef SNAPGFX
			case 's':
			      smartrefresh:{
					SnapRsrc->flags &= ~SIMPLEREFRESH;
					break;
				}
			case 'S':
			      simplerefresh:{
					SnapRsrc->flags |= SIMPLEREFRESH;
					break;
				}
#endif	/* SNAPGFX */
			case 'C':
			      cachesize:{
					if ( ARGVAL( ))
					{
						SnapRsrc->CacheSize = dectoint( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'L':
			      leading:{
					if ( ARGVAL( ))
					{
						SnapRsrc->Leading = dectoint( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'B':
			      badchar:{
					if ( ARGVAL( ))
					{
						SnapRsrc->BadChar = dectoint( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'F':
			      altfont:{
					if ( ARGVAL( ))
					{
						SetAltFont( *argv);
					}
					else
					{
						usage = 1;
					}
					break;
				}
			case 'Q':
			case 'q':
			      quit:{
					if ( create)
					{
						goto close;
					}
					else
					{
						Signal( SnapRsrc->Task, SIGBREAKF_CTRL_C);
						goto exitpoint;
					}
				}
			case '?':
				{
					usage = 1;
					break;
				}
			default:
				{
					SnapWriteStr( "Bad option: -");
					SnapWriteChar( ( int)**argv);
					SnapWriteStr( ".\n");
					usage = 1;
					break;
				}
			}
		}
		else
		{
#ifdef SNAPGFX
			char *keyword = *argv;

			*argv = NULL;
			if ( !stricmp( keyword, "PRIORITY"))
			{
				goto priority;	/* Terrible, ain't it? */
			}
			else if ( !stricmp( keyword, "TEXTQUAL"))
			{
				goto textqual;
			}
			else if ( !stricmp( keyword, "GFXQUAL"))
			{
				goto gfxqual;
			}
			else if ( !stricmp( keyword, "INSERTKEY"))
			{
				goto insertkey;
			}
			else if ( !stricmp( keyword, "CWKEY"))
			{
				goto cwkey;
			}
			else if ( !stricmp( keyword, "PREPEND"))
			{
				goto prepend;
			}
			else if ( !stricmp( keyword, "APPEND"))
			{
				goto append;
			}
			else if ( !stricmp( keyword, "CHARDELAY"))
			{
				goto chardelay;
			}
			else if ( !stricmp( keyword, "LINEDELAY"))
			{
				goto linedelay;
			}
			else if ( !stricmp( keyword, "CRAWLPTRN"))
			{
				goto crawlptrn;
			}
			else if ( !stricmp( keyword, "XEROX"))
			{
				goto xerox;
			}
			else if ( !stricmp( keyword, "NOXEROX"))
			{
				goto noxerox;
			}
			else if ( !stricmp( keyword, "EARLYPATCH"))
			{
				goto earlypatch;
			}
			else if ( !stricmp( keyword, "NOEARLYPATCH"))
			{
				goto noearlypatch;
			}
			else if ( !stricmp( keyword, "TRUEUNDERSCORE"))
			{
				goto realunderscore;
			}
			else if ( !stricmp( keyword, "FAKEUNDERSCORE"))
			{
				goto fakeunderscore;
			}
			else if ( !stricmp( keyword, "JOINLONG"))
			{
				goto joinlong;
			}
			else if ( !stricmp( keyword, "NOJOINLONG"))
			{
				goto nojoinlong;
			}
			else if ( !stricmp( keyword, "SIMPLEREFRESH"))
			{
				goto simplerefresh;
			}
			else if ( !stricmp( keyword, "SMARTREFRESH"))
			{
				goto smartrefresh;
			}
			else if ( !stricmp( keyword, "STARTUNIT"))
			{
				goto startunit;
			}
			else if ( !stricmp( keyword, "PLANEMASK"))
			{
				goto planemask;
			}
			else if ( !stricmp( keyword, "CACHESIZE"))
			{
				goto cachesize;
			}
			else if ( !stricmp( keyword, "LEADING"))
			{
				goto leading;
			}
			else if ( !stricmp( keyword, "BADCHAR"))
			{
				goto badchar;
			}
			else if ( !stricmp( keyword, "ALTFONT"))
			{
				goto altfont;
			}
			else if ( !stricmp( keyword, "QUIT"))
			{
				goto quit;
			}
			else if ( stricmp( keyword, "?"))
			{
				SnapWriteStr( "Bad switch/keyword: ");
				SnapWriteStr( keyword);
				SnapWriteStr( ".\n");
			}
#endif	/* SNAPGFX */
			usage = 1;
		}
	}

	if ( usage)
	{
		SnapWriteStr( "Usage:\n");
#ifdef SNAPGFX
		SnapWriteStr( " snap -pNN -tQQ -gQQ -iXX -wXX -Pstr -Astr -cNN -lNN\n");
		SnapWriteStr( "   -aXXXX -x -X -e -E -uN -r -R -j -J -s -S -bXX -CNN\n");
		SnapWriteStr( "   -LNN -BNN -Ffont -Q\n");
		SnapWriteStr( " or\n");
		SnapWriteStr( " snap PRIORITY/K TEXTQUAL/K GFXQUAL/K INSERTKEY/K CWKEY/K\n");
		SnapWriteStr( "   PREPEND/K APPEND/K CHARDELAY/K LINEDELAY/K CRAWLPTRN/K\n");
		SnapWriteStr( "   XEROX/S NOXEROX/S EARLYPATCH/S NOEARLYPATCH/S STARTUNIT/K\n");
		SnapWriteStr( "   TRUEUNDERSCORE/S FAKEUNDERSCORE/S JOINLONG/S NOJOINLONG/S\n");
		SnapWriteStr( "   SIMPLEREFRESH/S SMARTREFRESH/S PLANEMASK/K CACHESIZE/K\n");
		SnapWriteStr( "   LEADING/K BADCHAR/K ALTFONT/K QUIT/S\n");
#else
		SnapWriteStr( " snap -pNN -tQQ -iXX -Pstr -Astr -cNN -lNN\n");
		SnapWriteStr( "   -aXXXX -x -X -e -E -uN -r -R -j -J -bXX -CNN\n");
		SnapWriteStr( "   -LNN -BNN -Ffont -Q\n");
#endif	/* SNAPGFX */
		SnapWriteStr( "\n");
		SnapWriteStr( "S-Mail: Mikael Karlsson     | E-Mail: micke@slaka.sirius.se\n");
		SnapWriteStr( "        Lövsättersvägen 10  |         micke@slaka.UUCP\n");
		SnapWriteStr( "        S-585 98  LINKÖPING |         {mxvax|seismo}!sunic!liuida!slaka!micke\n");
		SnapWriteStr( "        Sweden              | Phone:  +46 ( 0)13 50479\n");
		goto exitpoint;
	}

      skipargs:
	freopen( "NIL:", "w", stdout);

	if ( !create)
	{
		/* Tell him there are new settings available */
		Signal( SnapRsrc->Task, SIGBREAKF_CTRL_F);
		goto exitpoint;
	}

	if ( !OpenStuff( ))
	{
		goto close;
	}

	textqual = SnapRsrc->textqual;
	gfxqual = SnapRsrc->gfxqual;
	insertkey = SnapRsrc->insertkey;
	cwkey = SnapRsrc->cwkey;
	TrueUnderscore = SnapRsrc->flags & TRUEUNDERSCORE ? 1 : 0;
#ifdef SNAPGFX
	SaveName[ 0] = '\0';
#endif

#ifdef SNAPREXX
	rexxsignal = upRexxPort( "SNAP", rcl, NULL, &disp);
#endif	/* SNAPREXX */

	/* This is what we're waiting for */
	WaitSignal = startsignal | insertsignal | initsignal | cancelsignal |
#ifdef SNAPREXX
		rexxsignal |
#endif	/* SNAPREXX */
		cwsignal | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F;

	FOREVER
	{
		REGISTER LONGBITS sig;

		sig = Wait( WaitSignal | timersignal
#ifdef SNAPGFX
			 | ( Sharedport ? ( 1L << Sharedport->mp_SigBit) : 0L)
#endif	/* SNAPGFX */
			);

#ifdef SNAPGFX
		CheckWindowMsgs( );
#endif	/* SNAPGFX */

#ifdef SNAPREXX
		if ( sig & rexxsignal)
		{
			dispRexxPort( );
		}
#endif	/* SNAPREXX */
		if ( sig & SIGBREAKF_CTRL_C)
		{
			/* This is my cue. Exit if there are no open windows depending on us */
#ifdef SNAPGFX
			if ( Sharedrefs)
			{
				DisplayBeep( NULL);
			}
			else
#endif	/* SNAPGFX */
			{
				goto close;
			}
		}
		if ( sig & SIGBREAKF_CTRL_F)
		{
			/* Hey, seems like there are new settings available. */
			textqual = SnapRsrc->textqual;
			gfxqual = SnapRsrc->gfxqual;
			insertkey = SnapRsrc->insertkey;
			cwkey = SnapRsrc->cwkey;
			TrueUnderscore = SnapRsrc->flags & TRUEUNDERSCORE ? 1 : 0;
		}
		if ( sig & initsignal)
		{
			if ( SnapRsrc->flags & ( XEROX | EARLYPATCH))
			{
				SafePatch( );	/* Patch dangerous functions */
			}
		}
		if ( sig & cancelsignal)
		{
			SafeRestore( );
		}
		if ( sig & startsignal)
		{		/* The handler wants a word in. */
			SafePatch( );
#ifdef SNAPGFX
			if ( action == snapgfx)
			{	/* Check user action */
				HandleGfx( );	/* Get the picture :-) */
			}
			else
#endif	/* SNAPGFX */
			if ( action == snaptext && HandleChars( ))
			{	/* Snap some chars */
				if ( SnapRsrc->flags & XEROX)
				{
					sig |= insertsignal;
				}
			}
			else
			{
				/* Previous snap wasn't finished when this one started
				   or this snap failed. */
				SetSignal( 0L, movesignal | cancelsignal |
				     donesignal | clicksignal | ticksignal);
				DisplayBeep( NULL);
				action = noaction;
			}
			if ( !( sig & insertsignal))
			{
				SafeRestore( );	/* Layers unlocked - all safe */
			}
		}

		if ( sig & insertsignal)
		{
			LONG i;
			struct Snap *Snap;
			ULONG ascii;

			action = insert;
			if ( Snap = FetchClip( ))
			{	/* Get clipboard data */
				/* get the current keymap  */
				ConIOR->io_Command = CD_ASKDEFAULTKEYMAP;
				ConIOR->io_Length = sizeof ( struct KeyMap);

				ConIOR->io_Data = ( APTR) & keymap;
				ConIOR->io_Flags = 1;	/* no IOQuick   */
				DoIO( ( struct IORequest *)ConIOR);
				/* Set up an input request */
				inputRequestBlock->io_Command = IND_WRITEEVENT;
				inputRequestBlock->io_Flags = 0L;
				inputRequestBlock->io_Length = ( long)sizeof ( struct InputEvent);

				inputRequestBlock->io_Data = ( APTR) & SimEvent;
				/* Translate chars in SnapSpace and insert them
				   into the input stream. */
				insertcount = 0;
				ascii = 13;	/* Simulate start of new line */
				for ( i = 0; Snap->Chars[ i] && ( action == insert); ++i)
				{
					if ( ascii == 13 && modinsert)
					{
						int cnt = 0;

						while ( ascii = SnapRsrc->Prepend[ cnt++])
						{
							InsertAscii( ascii);
						}
					}

					ascii = Snap->Chars[ i];
					if ( ascii == 10)
					{
						if ( modinsert)
						{
							int cnt = 0;

							while ( ascii = SnapRsrc->Append[ cnt++])
							{
								InsertAscii( ascii);
							}
						}
						ascii = 13;	/* WYSIWYG? Hah! */
					}
					InsertAscii( ascii);
					if ( ascii == 13 && SnapRsrc->linedelay)
					{
						MyTR.tr_node.io_Command = TR_ADDREQUEST;
						MyTR.tr_time.tv_micro = SnapRsrc->linedelay;
						MyTR.tr_time.tv_secs = 0;
						DoIO( ( struct IORequest *)&MyTR);
					}
				}
				if ( modinsert)
				{
					int cnt = 0;

					while ( ascii = SnapRsrc->Append[ cnt++])
					{
						InsertAscii( ascii);
					}
				}
				SafeRestore( );	/* "Depatch" */
				/* Free memory given to us by FetchClip( ) */
				FreeMem( Snap, Snap->Size);
			}
			action = noaction;
			modinsert = 0;
		}

#ifdef SNAPGFX
		if ( sig & cwsignal)
		{
			if ( !ControlWindow && !OpenCW( ))
			{
				DisplayBeep( NULL);
			}
		}
#endif	/* SNAPGFX */
	}

      close:
#ifdef SNAPREXX
	dnRexxPort( );
#endif	/* SNAPREXX */
	CloseStuff( );		/* Guess what */
      exitpoint:
	CloseLibs( );
#ifdef AZTEC_C
	return 0;
#endif
}
