** Introduction **
GSC is a GEMScript lib for Pure C using the standard AES binding pcgemlib.lib 
or the mt_aes.lib. It offers functions for acting as a "server" (receiving and 
executing GEMScript commands) or as a "client" (sending GEMScript commands). 
It does all of the GEMScript timeout, ACKnowledge stuff and so on.

The number of open connections is static, but can be changed by recompiling 
the lib. By default, 10 open connections as a server and 10 open connections 
as a client can be handled, and up to 50 GEMScript commands can be installed.

** Installation **
Copy the files from the folders "include" and "lib" into the according Pure C 
directories. Copy the other folders where you like.

GSC requires the HiTRIX library which is supplied with GSC. You need to add 
both GSC.LIB and HITRIX.LIB to your project. Another way is to link GSC.LIB 
and HITRIX.LIB into another lib.

** Usage **
This is only an overview.
For more details of using the functions see the source "gsc.c" in the folder
"source". Also, you can look at gsctest.c, in which a simple GEMScript 
example is programmed. Every function is commented with a description of it's 
arguments.
"access" in the description of arguments describes the way an argument is used:
"w" means write a value into this argument before calling the function, "r" 
means the function returns a value in this parameter and "v" means this 
parameter may be left NULL.

The GSC lib uses the EVENT struct and the function EvntMulti() of the standard 
PC AES binding. If you use mt_aes.lib, this struct and the function EvntMulti 
are made available by GSC. The event struct must be set AT LEAST to a MU_TIMER 
event with at minimum 500 ms and a MU_MESAG event. Other events may be used if 
you like.

The GSC lib works mainly with callbacks. Due to this, always a user handler 
must be installed, which is called while GSC waits for acknowledge when a 
command is sent. The user callback has to evaluate all events during this; 
otherwise events would be lost while waiting for acknowledge.

 * the user event handler *
 **************************

 must have this form:
 BOOLEAN user_event_handler( EVENT *evnt )
 {
 	switch( evnt->ev_mwich )
 	{
 		case MU_MESAG:
 		  ...
 		  break;
 		  ...
 	}
 	return( FALSE );
 }
 the handler is handed over a pointer to the current event struct. Evaluate 
 evnt->ev_mwich to see which event has occurred. The return value of this 
 function isn't used in the standalone version. Always return "FALSE" here.
 Always use the handed over EVENT struct pointer instead of possible 
 global EVENT struct vars.
 This event handler has got nothing to do with GEMScript! Handlers for 
 GEMScript commands must be declared separately (see below). Only the common 
 events like AP_TERM, MN_SELECTED, window messages, keyboard, mouse... events 
 are to be handled here. You needn't evaluate no GEMScript messages, this is 
 done by GSC itself.

 * Initialisation and exit *
 ***************************

 At first init your EVENT struct to at least MU_MESAG | MU_TIMER (max. 500 ms).
 Then do your common AES init stuff: appl_init(), rsrc_load() and so on.
 Inititialize the GSC lib with Gsc_sinit(). Don't use Gsc_init(), this is used 
 for the non-standalone version, which is part of a bigger lib. Gsc_sinit() 
 must be handed over your application id, a pointer to the EVENT struct and a 
 pointer to your event handler. Only a copy of the EVENT struct is used! If 
 you want to change the values of the EVENT struct or want to change the 
 handler, use Gsc_set_evnt() to update the event struct in the lib.

 * the event loop *
 ******************

 your event loop should look like this:
 for(;;)
 {
 	EvntMulti( &Evnt );
 	Gsc_exec( &Evnt );
 	user_event_handler( &Evnt );
 }
 Gsc_exec() does all of the stuff which must be done to handle GEMScript 
 commands: evaluate messages, send ACKs, wait for ACKs, timeout etc. If an 
 event occurs which is evaluated by Gsc_exec(), the according flag in 
 evnt.ev_mwich is deleted.

 * GSC as a "server" *
 *********************

 Adding GEMScript commands to your application is very simple.
 Simply declare a handler for the GEMScript command you want to install:
 WORD gs_my_command( BYTE *cmd, LONG cmdid, BYTE *cmdlin, BYTE *ret )
 {
 	...

 	return( GSACK_OK );
 }
 Install this handler by Gsc_cbk_set() (means GEMScript_callback_set()). 
 Gsc_cbk_set() must be handed over the command in ascii you want to install, 
 e.g. "MyCommand", a user defined id (choose yourself) and a pointer to the 
 above handler.

 this handler is called by Gsc_exec() and is handed over the following 
 variables:
 - the command in ascii
 - the user defined id.
 - the GEMScript command line in asciizz notation (several strings, as much as 
   parameters, ended by a double \0. Like in the environment.
 - a pointer to an already allocated global string buffer, which is returned 
   to the calling application as the return string in ASCIIZZ format.
   You may write anything else you like, e.g. return your programs name or a 
   version string, but always in ASCIIZZ notation. E.g. in the command 
   "AppGetLongName" you should set this string to "My program name\0". (You 
   can use the Str_asciizz..()-functions of the hitrix lib for this). In the 
   GEMScript doc it is declared, that this ASCIIZZ string should be a "1\0" or 
   sth else to return a TRUE to the calling application and a "\0" (empty 
   ASCIIZZ string) to return a FALSE.
   So the return string is preseted by a "1\0". If you don't want to 
   return anything special in this string, you needn't change it at all; if 
   you return GSACK_ERROR (see below), the return string is cleared 
   automatically, and if you return GSACK_OK, the return string is left 
   unchanged, so you needn't change it at all.
   Note: the length of this string is static and it's declared in the constant
   GSC_MAXCMDLEN (by default 512, may be changed by recompiling). So if your 
   application has many GEMScript-commands, be sure that the overall length of 
   all your commands including string end null bytes and an additional 
   null byte for the ASCIIZZ string doesn't exceed this length; otherwise the 
   builtin GEMSCript command GetAllCommands() will crash! You will have to 
   recompile the GSC lib with bigger buffers (set GSC_MAXCMDLEN to a bigger 
   value) in that case.
 the handler should return one of the following values (as declared in 
 the GEMScript doc 1.2):
 GSACK_OK: everything's fine, the command is done
 GSACK_ERROR: something's wrong, command could not be executed
 ( GSACK_UNKNOWN, the acknwowledge for unknown function, needn't be returned, 
 because this is handled by GSC automatically )

 an installed handler may be removed via Gsc_cbk_remove() or may be set active 
 or inactive by Gsc_cbk_active().

 * GSC as a "client" *
 *********************

 There are two ways to call other applications via GEMScript: a simple one and 
 a more complicated, but slightly more flexible. Here only the simple way 
 shall be described. Read the comments of gsc.c to learn about using the other 
 way.
 you can simply call a GEMScript command by Gsc_command().
 To this function, you have to hand over the following parameters:
 - the name of the Application - this may be the short name of the app (e.g. 
   "RASN.APP"/"rasn.app") or the appl_find()-name ("RASN    ") or the name 
   without extender ("RASN").
 - the command, e.g. "Sound"
 - the commandline, always as an ASCIIZZ string. Empty parameters are set by an
   "\1".
   example: "arg1\0" is a single parameter called 'arg1'
            "arg1\0arg2\0" are two parameters, 'arg1' and 'arg2'
            "arg1\0\1\0arg3\0" are parameter 'arg1', an empty parameter and 
                               parameter 'arg3'.
                               'arg1', <empty parameter>, 'arg3'
            "arg1" THIS IS WRONG! It has always to be an ASCIIZZ string!
 - a timeout in seconds.

 Gsc_command() returns 2 parameter values (optional):
 - the return code of the called application (GSACK_OK, GSACK_ERROR, 
   GSACK_UNKNOWN)
 - a pointer to a copy of the return ASCIIZZ string of the application.
   This copy is valid until the next Gsc_command, Gsc_xcommand(), 
   Gsc_parsecommand(), Gsc_xparsecommand() or Gsc_send(), so be sure to copy 
   or duplicate it, if you need it for a longer time!

 The return value of Gsc_command can be either 0 (everything went fine)
 or one of the following errorcodes (declared in gsc.h):
 #define E_GSC_OK 0              /* fine */
 #define E_GSC_BUSY -1           /* connection busy */
 #define E_GSC_TIMEOUT -2        /* connection has timed out */
 #define E_GSC_ERROR -3          /* connection refused by remote */
 #define E_GSC_OFFLINE -4        /* no connection established */
 #define E_GSC_APPNTFND -5       /* remote application not found */
 #define E_GSC_SYNTAX -6         /* syntax error in command */
 #define E_GSC_MEM -7            /* out of memory while allocating buffers */
 #define E_GSC_TOOMUCHAPPS -8    /* too much open connections (see 
                                    compiling GSC) */
 #define E_GSC_NOTSENT -9        /* nothing was sent when trying a Gsc_get() 
                                    */
 #define E_GSC_DELIVERED -10     /* there's still a message in buffer when 
                                    trying to send a new message, use 
                                    Gsc_get() before Gsc_send() */
 #define E_GSC_WRONGEVNT -11     /* you called Gsc_command without the 
                                    MU_MESAG flag set in your Event struct. 
                                    Set it as described. */
 #define E_GSC_QUIT -12          /* the remote has sent a GS_QUIT (even during 
                                    a running command) Close this connection 
                                    asap */
 #define E_GSC_WRONGID -13       /* wrong user ID when sending a command to a 
                                    remote app. Choose another one.
                                    This error code is really stupid... and it 
                                    will never be sent by GSC acting
                                    as a server. But it may occur, when other 
                                    applications refuse a connection
                                    this way, especially when you choose the 
                                    "forbidden" ID -1 in a command. */

 Gsc_parsecommand() does a very simple commandline parsing using the Scripter 
 Syntax.

 Gsc_exec() sends a GS_ACK responding to the remote's GS_ACK automatically. In 
 some special cases this is a problem, especially when the remote's return 
 string is to be evaluated before the last GS_ACK (e.g. Jinnee.GetIcon()).
 In this case there are special functions Gsc_xcommand() and 
 Gsc_xparsecommand(), which allow to evaluate the return string before the 
 final GS_ACK.

 * compiling the GSC lib *
 *************************
 this lib is made with pure c and only tested with this. If you use another 
 compiler, there will be a problem with the hitrix.lib, for which sources 
 aren't released yet (don't look very nice...). Maybe this will change. But at 
 this time, if you want to compile GSC on another compiler than Pure C, 
 contact me and I will send you the missing sources of the HITRIX.LIB.

 If you want to compile the gsc.c, one compiler switch must be always set: 
 GSC_STANDALONE. Otherwise the lib would be compiled as a part of a bigger lib.

 Another compiler switch is GSC_USE_MTAES. Declare it if you want to use the 
 MT_AES.LIB, otherwise leave it undeclared.

 The following defines (declared in GSC.H) are responsible for the limits of 
 the lib:

 #define GSC_VERSION 0x0120  /* Gemscript-version, currently 1.20 */
 #define GSC_MAXAPPS 10      /* max nr of open connections to applications (as 
                                "server") */
 #define GSC_MAXSENDAPPS 10  /* max nr of open connections to applications 
                                (as "client") */
 #define GSC_MAXCMDLEN 512   /* max length of a command and it's answer */ 
 #define GSC_MAXCMD 50       /* max number of commands to install */

 * The usage of the demo program *
 *********************************

 "RASN Sample abspielen" plays the startup sample of Rational Sounds via 
   GEMScript. This is a simple example how to play a sample in Rational Sounds.

 "Kommando interpretieren" opens a dialog, in which you can enter a GEMScript
   Command in Scripter syntax (
   e.g. App.command( "parameter 1".., "", "parameter n" ); )
   this is interpreted and executed and a dialog for the return values is 
   displayed. The first displayed value is the return value of 
   Gsc_parsecommand(); if it's != 0 (error), see the E_GSC_... errormessages 
   in gsc.h for the meaning.

 "Applikation abfragen" shows the gs_info struct of an app

 "Alle Kommandos abfragen" asks all of the commands of an application by the 
 GEMScript command GetAllCommands(). The result is printed directly on the 
 screen. Try entering gscdemo as an application here and you will see all 
 commands which are implemented in this demo program.





