


/*
	This  program is a simple example of how programs written in C (and
other languages) can control CygnusEd Professional.  All communication with
CygnusEd  Professional is done with messages.  A special message structure,
CedMsg  is  used  for  this  communication.  An ascii string containing the
command  is  put  in  the  cm_Args[0] field, an optional flag bit is put in
rm_Action and the result are returned in rm_Result1 and rm_Result2.

	For further information on the interface, please consult the manual
that comes with CygnusEd Professional.

	Also  note  that  since  ARexx  is designed to interface with other
programs  it  does  a  much  better  job of it - it's easier to write ARexx
programs  that  interface  with  CygnusEd  Professional  than  C  programs.
Consider buying ARexx if you want to control the editor.

	This  program  was  compiled  under  Aztec 3.6 but should work fine
under Lattice and any other compilers.

*/



#include	"intuition/intuitionbase.h"

/*
	Various  other  include  files  are  probably  needed,  but  I  use
precompiled  include files and I don't need to specify them so I don't know
if  any  others  are  needed or not.  Just include everything and it should
work :-)

*/



#define RXFB_RESULT  17

struct CedMsg
{
	struct Message cm_Node;
	LONG   RFU1;
	LONG   RFU2;
	LONG   rm_Action;
	LONG   rm_Result1;
	LONG   rm_Result2;
	char   *cm_Args[16];
	LONG   RFU7;
	LONG   RFU8;
	LONG   RFU9;
	LONG   RFU10;
	LONG   RFU11;
	LONG   RFU12;
};

struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;
struct Screen		*screen;		/* This global variable is required by the 'okay' function. */
struct CedMsg	TheMessage;
struct MsgPort	*CedPort, *MyPort;



/*
	This   routine   sends   an   ascii   string  command  to  CygnusEd
Professional.   It  deals with the messy business of setting up the message
etc.   It  returns  TRUE or FALSE to say whether or not the send succeeded.
Any  error  codes  from  CygnusEd  Professional  will  be  returned  in the
rm_Result1 field of the message.

*/

BOOL SendCygnusEdMessage(thecommand)
char	*thecommand;
{
	TheMessage.cm_Args[0] = thecommand;
	TheMessage.cm_Node.mn_Node.ln_Type = NT_MESSAGE;
	TheMessage.cm_Node.mn_Length = sizeof(struct CedMsg);
	TheMessage.rm_Action = 0;	/* We don't want results. */
	TheMessage.rm_Result2 = 0;	/* clear out the last result. */
	Forbid();
	if (!(CedPort = FindPort("rexx_ced"))) return((BOOL)FALSE);
	if (!(MyPort = CreatePort("MyPort", 0L))) {
		Permit();
		return((BOOL)FALSE);
	}
	TheMessage.cm_Node.mn_ReplyPort = MyPort;
	PutMsg(CedPort, &TheMessage);
	WaitPort(MyPort);
	DeletePort(MyPort);
	Permit();
	return((BOOL)TRUE);
}



/*
	If  information  is  requested from CygnusEd Professional (with the
SendCygnusEd ProfessionalMessageGetReply() function probably) and the value
returned is a string (as opposed to just a number) then the chunk of memory
containing  the  string must be freed.  This routine does this, finding the
length in the long word preceding the string.

*/

FreeMyString(location)
char	*location;
{
	long	*RealLocation;

	if (!location) return;
	RealLocation = (long *)location;
	RealLocation--;
	FreeMem(RealLocation, *RealLocation);
}



/*
	This  routine is used for sending commands to CygnusEd Professional
when you want a response.  Certain commands, such as the status command can
return  strings  or  numbers  telling  you  something  about the success or
failure  of the command or about the internal status of the editor.  If the
command  returns  a string, you are responsible for freeing the memory used
to  store  the  string.   The  FreeMyString  command  is  provided for this
purpose.

*/

BOOL SendCygnusEdMessageGetReply(thecommand)
char	*thecommand;
{
	TheMessage.cm_Args[0] = thecommand;
	TheMessage.cm_Node.mn_Node.ln_Type = NT_MESSAGE;
	TheMessage.cm_Node.mn_Length = sizeof(struct CedMsg);
	TheMessage.rm_Action = 1L << RXFB_RESULT;	/* We do want results. */
	TheMessage.rm_Result2 = 0;	/* clear out the last result. */
	if (!(CedPort = FindPort("rexx_ced"))) return((BOOL)FALSE);
	if (!(MyPort = CreatePort("MyPort", 0L))) return((BOOL)FALSE);
	TheMessage.cm_Node.mn_ReplyPort = MyPort;
	PutMsg(CedPort, &TheMessage);
	WaitPort(MyPort);
	DeletePort(MyPort);
	return((BOOL)TRUE);
}

char *messagelist1[] =
{
	"open new",
	"expand window",
	"text This  is  a  simple  program  to  show  how simple it is to write\n",
	"text programs  that  can  control  CygnusEd  Professional, the amazing\n",
	"text editor from:\n",
	"text                   CygnusSoft Software\n",
	"text \n",
	"text \n",
	"beg of file",
	"mark block",
	"end of file",
	"copy block",
	"text      Now I will demonstrate how you can ask CygnusEd Professional\n",
	"text for  information on the status of many of CygnusEd Professional's\n",
	"text internal  variables.   The  values  of  these  variables are then\n",
	"text displayed with the 'okay1' command.\n",
	"text \n",
	"text \n",
	(char *) 0,
};



/*
	If you pass this function a pointer to an array of string pointers,
terminated with a zero, then this routine will send the strings to CygnusEd
Professional as commands, one at a time.

*/

SendCygnusEdMessages(messages)
char	*messages[];
{
	while (*messages) SendCygnusEdMessage(*messages++);
}



/*
	This routine cleans up all allocated resources.

*/

quit_cleanup(message)
char	*message;
{
	if (message) {
		if (IntuitionBase && GfxBase) okay(message, 1L);
		else puts(message);
	}
	if (GfxBase) CloseLibrary(GfxBase);
	if (IntuitionBase) CloseLibrary(IntuitionBase);
	if (message) exit(10);
	exit(0);
}



/*
	This program is a demonstration of how to interface C programs with
CygnusEd  Professional  and  it  is  also  a  demonstration  of some of the
commands  you  can  use when controlling CygnusEd Professional from another
program.

*/

main()
{
	int		i;
	char	tempstring[300];


	/* These are required for the 'okay' function built into this program */
	/* that is only used if this program can not find CygnusEd in memory. */
	/* If we wish to recompile this program you will have to take out the */
	/* call to the 'okay' routine because this routine is from our private */
	/* library. */

	if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 33L)))
		quit_cleanup("Requires 1.2");
	if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 33L)))
		quit_cleanup("No paint!");


	/* First try to bring CygnusEd Professional to the front.  If the */
	/* message sending command fails then CygnusEd probably isn't in */
	/* memory.  At this point the program can either run the editor */
	/* or print a message and exit.  I decided to print a message so that */
	/* people will realize what is happening. */

	if (!SendCygnusEdMessage("cedtofront"))
		quit_cleanup("CygnusEd is not in memory.\n"
			 "You must run it before you\n"
			 "can run this demo.");


	/* Send a whole list of messages to CygnusEd Professional. */

	SendCygnusEdMessages(messagelist1);


	/* Find out the status of some of CygnusEd Professional's internal flags.  No */
	/* particular reason, just to show how it's done. */

	SendCygnusEdMessageGetReply("status 1");	/* Interlace? */
	sprintf(tempstring, "okay1 'Interlace?' is %ld.", TheMessage.rm_Result2);
	SendCygnusEdMessage(tempstring);

	SendCygnusEdMessageGetReply("status 2");	/* Hot start enabled? */
	sprintf(tempstring, "okay1 'Hot start enabled?' is %ld.", TheMessage.rm_Result2);
	SendCygnusEdMessage(tempstring);

	SendCygnusEdMessageGetReply("status 3");	/* Forcecustom screen? */
	sprintf(tempstring, "okay1 'Force custom screen?' is %ld.", TheMessage.rm_Result2);
	SendCygnusEdMessage(tempstring);


	/* Get a copy of the custom tabs string.  Don't forget to free */
	/* up the string when finished looking at it. */

	SendCygnusEdMessageGetReply("status 7");	/* custom tabs */
	sprintf(tempstring, "okay1 'Custom tabs' are \n'%s'.", TheMessage.rm_Result2);
	FreeMyString(TheMessage.rm_Result2);		/* Be sure to free the string */
							/* before calling another command. */
							/* Otherwise the pointer will get */
							/* zeroed. */
	SendCygnusEdMessage(tempstring);


	/* Insert many copies of the block cut out earlier. */

	for (i = 0; i < 18; i++) SendCygnusEdMessage("insert block");


	/* Guess what this does?  I'll give you a hint - 79 is a left arrow */
	/* key and 10 is SHIFT and CTRL pressed at the same time.  78 is a */
	/* right arrow key. */

	for (i = 0; i < 50; i++) SendCygnusEdMessage("rawkey 79 10");

	for (i = 0; i < 50; i++) SendCygnusEdMessage("rawkey 78 10");


	/* Let's make sure the editor is in interlaced mode. */

	SendCygnusEdMessageGetReply("status 1");	/* Interlace? */
	if (!TheMessage.rm_Result2) SendCygnusEdMessage("interlace");

	/* Let's make sure the active view is full size. */

	SendCygnusEdMessage("expand view");


	/* Let's highlight the whole file and then rotate it */

	SendCygnusEdMessage("beg of file");
	SendCygnusEdMessage("mark block");
	SendCygnusEdMessage("end of file");
	SendCygnusEdMessage("rot block");


	/* Now let's do a mark block at the bottom and scroll up (in the */
	/* fastest scrolling speed and then rotate it again - to straighten */
	/* the other rotation. */

	SendCygnusEdMessage("mark block");
	SendCygnusEdMessage("8 pixels");
	for (i = 0; i < 130; i++)
		SendCygnusEdMessage("rawkey 76 0");
	SendCygnusEdMessage("rot block");


	/* Now I go down to the bottom of the screen and then scroll back up, */
	/* with the scroll jump gradually increasing and the scrolling speed */
	/* therefore gradually increasing. */

	SendCygnusEdMessage("end of screen");
	SendCygnusEdMessage("1 pixel");
	for (i = 0; i < 60; i++)
		SendCygnusEdMessage("rawkey 76 0");		/* We could also use the 'up' command here. */
	SendCygnusEdMessage("2 pixels");
	for (i = 0; i < 15; i++)
		SendCygnusEdMessage("rawkey 76 0");		/* We could also use the 'up' command here. */
	SendCygnusEdMessage("4 pixels");
	for (i = 0; i < 15; i++)
		SendCygnusEdMessage("rawkey 76 0");		/* We could also use the 'up' command here. */
	SendCygnusEdMessage("8 pixels");
	for (i = 0; i < 30; i++)
		SendCygnusEdMessage("rawkey 76 0");		/* We could also use the 'up' command here. */
	SendCygnusEdMessage("1 pixel");


	/* That's it.  I hope you enjoyed the demo. */

	SendCygnusEdMessage("okay1 That's it.  I hope you enjoyed the demo.");
}
