/// Revision Header
/* $Revision Header built automatically *************** (do not edit) ************
**
** © Copyright by SA Productions
**
** File             : User:Prog/MyGoldEd/ged.c
** Created on       : Onsdag, 02.11.94 10:44:04
** Created by       : Søren Berg Glasius
** Current revision : V1.3
**
**
** Purpose
** -------
**     A quickstart replacement for GoldED. The quickstarter 
**     supplied with GoldED did not satisfy my requirements, and 
**     then I decided to create my own. 
**     Please note, that some of the code is taken from the 
**     original source supplied with GoldED.
**
** Revision V1.3
** --------------
** created on Onsdag, 12.04.95 18:53:34  by  Søren Berg Glasius.   LogMessage :
**   - Removed a nasty bug, that sometimes opened multiple
**     files, if the file requested does not exists. 
**
** Revision V1.2
** --------------
** created on Tirsdag, 07.02.95 12:34:15  by  Søren Berg Glasius.   LogMessage :
**  -*-  created on Tirsdag, 07.02.95 12:34:15  by  Søren Berg Glasius.   LogMessage :
**   - Now changed to be used with GoldED 2.0. This made the 
**     configuration-load-scheme a bit easier. Now I don't have
**     to save what config is loaded the last time. GoldED knows
**     the current pref.
**     The GoldED/GED_AUTOCFG has changed to GED_AUTOCFG
**
** Revision V1.1
** --------------
** created on Onsdag, 21.12.94 13:57:10  by  Søren Berg Glasius.   LogMessage :
**  -*-  changed on Onsdag, 21.12.94 13:59:20  by  Søren Berg Glasius.   LogMessage :
**   - The program can now be made resident.
**  -*-  changed on Onsdag, 21.12.94 13:58:37  by  Søren Berg Glasius.   LogMessage :
**   - Two new switches has been added:
**     I=IGNOREENV/S: Ignore if GED_AUTOCFG is set.
**     F=FORCEPREF/S: Read the config for a given extension,
**     even if it's already loaded.
**  -*-  created on Onsdag, 21.12.94 13:57:10  by  Søren Berg Glasius.   LogMessage :
**   - Change in behaviour: ged now recognize the file extension
**     and loads a config file according to this extension. This 
**     requires the prefs to be named according to the extension of
**     the file (eg. .c extension has a pref file called "c.prefs")
**
** Revision V1.0
** --------------
** created on Søndag, 06.11.94 17:03:11  by  Søren Berg Glasius.   LogMessage :
**  -*-  changed on Onsdag, 07.12.94 16:47:14  by  Søren Berg Glasius.   LogMessage :
**   - Bugfix: When started the first time with a config specified,
**     this config would be loaded twice. The same applied for the
**     public screen given.
**  -*-  created on Søndag, 06.11.94 17:03:11  by  Søren Berg Glasius.   LogMessage :
**   - Now handles files loaded from the current dir correctly.
**  -*-  changed on Onsdag, 02.11.94 11:27:51  by  Søren Berg Glasius.   LogMessage :
**   - Differences between this version and the original ged:
**     1) Can load new configuration even is GoldEd is started.
**     2) Can change screen even if GoldEd is started.
**     3) Actually releases it self and returns to shell, if sticky
**        mode is not wanted.
**     4) Most important: It supports wildcards!
**  -*-  changed on Onsdag, 02.11.94 10:52:32  by  Søren Berg Glasius.   LogMessage :
**   - This version does not support WorkBench startup 
**     (eg. it does not read the tool types from an icon)
**     It will be included in a later version (I just gotta figure out
**     Dietmars original code first :-)
**  -*-  created on Onsdag, 02.11.94 10:44:04  by  Søren Berg Glasius.   LogMessage :
**     --- Initial release ---
**
*********************************************************************************/
#define REVISION "1.3"
#define REVDATE  "12.04.95"
#define REVTIME  "18:53:34"
#define AUTHOR   "Søren Berg Glasius"
#define VERNUM   1
#define REVNUM   3

#define VERSTAG "$VER: ED/GED " REVISION " (" REVDATE ")"
char *version=VERSTAG;
///

/// Includes

#include <exec/exec.h>

#include <dos/dos.h>
#include <dos/dostags.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>

#include <rexx/errors.h>
#include <rexx/rxslib.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/rexxsyslib.h>

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <dos.h>


/*__MemPoolFlags = MEMF_CLEAR | MEMF_PUBLIC;*/
extern struct DosLibrary *DOSBase;
///

/// Prototypes for functions
void changePrefs(char *ext, BOOL forceprefs,char *host, struct MsgPort *reply);
char *LookForGED(void);
char *StartGED(void);
ULONG *SendRxCmd(char *,char *, struct MsgPort *);
///

/// Template for ReadArgs
#define TEMPLATE (APTR)"FILES/M,C=CONFIG/K,S=SCREEN/K,HIDE/S,-STICKY/S,Y=STICKY/S,L=LINE/N,F=FORCEPREF/S,I=IGNOREENV"
#define T_FILES     0
#define T_CONFIG    1
#define T_SCREEN    2
#define T_HIDE      3
#define T_STICKY    4
#define T_STICKY2   5
#define T_LINE      6
#define T_FORCEPREF 7
#define T_IGNOREENV 8
#define T_COUNT     9
///

/// int main(void);
/* ----------------------------------- main ------------------------------------

 FUNCTION: Startup code for Shell/CLI

 INPUT: None

 RESULT: Returncode that reflect if anything went wrong

 -----------------------------------------------------------------------------*/

int main(void)
{
    LONG                  opts[T_COUNT];
    struct RDArgs        *rda;
    struct AnchorPath    *ap=NULL;
    struct MsgPort       *reply=NULL;
    char                 *host=NULL;
    char                **files;
    char                 *buf=NULL;
    char                 *cmd=NULL;
    char                 *ext=NULL;
    int                   apErr;
    int                   i;
    ULONG                *rc=NULL;


    for(i=0;i<T_COUNT;i++) opts[i]=0;

    if(!(rda=ReadArgs(TEMPLATE, opts, NULL))) {
        PrintFault(IoErr(),NULL);
        return RETURN_FAIL;
    }

    // Start new GoldED if not already present.
    if(!(host=LookForGED())){
        host = StartGED();
    }

    // Is there a host running now?
    if(host) {
        if(reply = CreateMsgPort()) {
            if(cmd=(char *)malloc(255)) {

                // Should we open on a specific public screen?
                if(opts[T_SCREEN]) {
                    sprintf(cmd,"SCREEN USE %s",(char *)opts[T_SCREEN]);
                    SendRxCmd(host, cmd, reply);
                }

                // Should we change the configuration?
                if(opts[T_CONFIG]) {
                    // Change it always, or only when changed?
                    if(opts[T_FORCEPREF])
                        sprintf(cmd,"PREFS CONFIG %s LOAD",(char *)opts[T_CONFIG]);
                    else
                        sprintf(cmd,"PREFS CONFIG %s LOAD SMART",(char *)opts[T_CONFIG]);
                    SendRxCmd(host, cmd, reply);
                }

                // Lock the display
                if ( rc = SendRxCmd(host, "LOCK CURRENT", reply)) {
                    if(*rc == RC_OK) {

                        // No files given and don't hide.
                        if(!opts[T_HIDE] && !opts[T_FILES])
                            SendRxCmd(host, "MORE SMART", reply);

                        // Files given and don't hide.
                        if(!opts[T_HIDE] && opts[T_FILES]) {
                            if(buf=(char *)malloc(255)) {
                                if(ext=(char *)malloc(255)) {
                                    files=(char **)opts[T_FILES];
                                    if(ap = (struct AnchorPath *)malloc(sizeof(struct AnchorPath)+255)) {
                                        ap->ap_Strlen=254;
                                        ap->ap_BreakBits=NULL;
                                        ap->ap_Flags=0;

                                        // Changing to the current directory. Opening a
                                        // file with a path should be no problem.
                                        GetCurrentDirName(buf, 254);
                                        sprintf(cmd,"DIR NEW %s",buf);
                                        SendRxCmd(host, cmd, reply);


                                        // Find all files, including wildcards.
                                        while(*files) {
                                            strcpy(buf,*files);
                                            apErr = MatchFirst(buf,ap);

                                            // If no file is found, open empty file!
                                            if(apErr==ERROR_OBJECT_NOT_FOUND) {

                                                // Open file with "*filename", if it does not
                                                // contain wildcards!
                                                if(!ParsePattern(*files,buf,255)) {
                                                    sprintf(cmd,"OPEN QUIET SMART %s",*files);
                                                    SendRxCmd(host, cmd, reply);

                                                    // Know the extension of the file opened.
                                                    stcgfe(ext,*files);
                                                }
                                            }
                                            // else open all matches for the wildcard!
                                            while(apErr!=ERROR_NO_MORE_ENTRIES && apErr!=ERROR_OBJECT_NOT_FOUND) {

                                                // Open each file seperatly.
                                                sprintf(cmd,"OPEN QUIET SMART %s",ap->ap_Buf);
                                                SendRxCmd(host, cmd, reply);

                                                // Know the extension of the file opened.
                                                stcgfe(ext,ap->ap_Buf);
                                                apErr = MatchNext(ap);
                                            }
                                            *files++;
                                        }
                                        free(ap);
                                    }

                                    // Should we jump to a specific line in the last opened file?
                                    // (sideeffect: this only works for the last file opened.)
                                    if(opts[T_LINE]) {
                                        sprintf(cmd,"GOTO LINE=%ld UNFOLD=TRUE",*(LONG *)opts[T_LINE]);
                                        SendRxCmd(host, cmd, reply);
                                    }

                                    // Should the appropiate environment be
                                    // loaded. Only if the env variable GED_AUTOCFG is set.
                                    // If Config file is already specified, don't change it here.
                                    //
                                    // Note: We can only do this on the last file loaded.
                                    //       (actually it could be done for all files, but what a mess!)

                                    if(!opts[T_IGNOREENV] && !opts[T_CONFIG] &&
                                        strlen(ext)       && (GetVar("GED_AUTOCFG",buf,255,NULL)!=-1))
                                        changePrefs(ext,(BOOL)opts[T_FORCEPREF],host,reply);

                                    free(ext);
                                }
                                free(buf);
                            }
                        }
                        // Should we run in sticky mode
                        // (Sideeffect: Sticks only to the last file opened.)
                        SendRxCmd(host, (opts[T_STICKY] || opts[T_STICKY2]) ? "UNLOCK STICKY" : "UNLOCK", reply);
                    }
                }
                free(cmd);
            }
            DeleteMsgPort(reply);
        }
    }
    FreeArgs(rda);

    // Makes a clean exit always!

    return RETURN_OK;


}
///

/// void changePrefs(char *ext, BOOL forceprefs,char *host, struct MsgPort *reply)
/* -------------------------------- changePrefs --------------------------------

 FUNCTION: Calls GoldED to change the current preference.

 INPUT: the extension of the pref to load, the host and the msgporg

 RESULT: (void)

 -----------------------------------------------------------------------------*/

void changePrefs(char *ext, BOOL forceprefs,char *host, struct MsgPort *reply)
{
    // GoldED now supports smart config loading - we will just tell GoldED to
    // change the prefs in the SMART way.

    char *pref;
    char *cmd;
    BPTR l;

    if(pref=(char *)malloc(100)) {
        if(cmd=(char *)malloc(100)) {
            sprintf(pref,"GoldED:config/%s.prefs",ext);
            if(l=Lock(pref,ACCESS_READ)) {
                UnLock(l);
                sprintf(cmd,"PREFS CONFIG \"%s\" LOAD SMART",pref);
                SendRxCmd(host, cmd, reply);
            }
            free(cmd);
        }
        free(pref);
    }
}
///

/// char *LookForGED(void)
/* -------------------------------- LookForGED ---------------------------------

 FUNCTION: Check if any GoldEd (1..9) is running

 INPUT:    void

 RESULT:   (char *) Name of running ged;

 -----------------------------------------------------------------------------*/

char *LookForGED(void)
{
    static char host[] = "GOLDED.1";
    UWORD num;

    // Check for all running versions of GoldED (returns the first one found).
    for(num='1'; num<='9'; num++) {
        host[7]=num;
        if (FindPort(host)) return (host);
        return(NULL);
    }
}
///

/// char *StartGED(void)
/* --------------------------------- StartGED ----------------------------------

 FUNCTION: Will start GoldEd, if it's not resident in memory

 INPUT: (BOOL)Start hidden, (char *)Screen Name, (char *)Config File

 RESULT: (char *)ArexxPort name.

 -----------------------------------------------------------------------------*/

char *StartGED(void)
{
    static char host[] = "GOLDED.1";

    // Run GoldED hidden in the background
    if (!SystemTags("GoldED:GoldED HIDE",
                    SYS_Asynch, TRUE,
                    SYS_Input, NULL,
                    SYS_Output, NULL,
                    NP_StackSize, 8*1024,
                    NP_ConsoleTask, NULL,
                    NP_WindowPtr, NULL,
                    TAG_DONE)) {
        int wait=0;
        DeleteVar("GoldED/GED_CURRENTPREF",NULL);
                
        // Wait to see, if it really started
        while (!FindPort(host) && (wait < 50)){
            wait++;
            Delay(10);
        }
    }

    // Did we find a running instance of GoldEd?
    if (FindPort(host)) return(host);

    return(NULL);
}
///

/// ULONG *SendRxCmd(char *port,char *cmd, struct MsgPort *replyPort)
/* ---------------------------------- SendRexxCommand -------------------------

 FUNCTION: Send ARexx message & wait for answer.

 INPUT: The port of the command, command, and the port of the reply.

 RESULT: Return pointer to result or NULL.

   --------------------------------------------------------------------------*/

ULONG *SendRxCmd(char *port,char *cmd, struct MsgPort *replyPort)
{
    struct MsgPort *rexxport;

    Forbid();
    if (rexxport = FindPort(port)) {

        struct RexxMsg *rexxMsg, *answer;
        if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {

            if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {

                static ULONG result;

                rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
                PutMsg(rexxport, &rexxMsg->rm_Node);
                do {
                    
                    WaitPort(replyPort);
                    if (answer = (struct RexxMsg *)GetMsg(replyPort))
                        result = answer->rm_Result1;

                } while (!answer);

                Permit();
                if (answer->rm_Result1 == RC_OK) 
                    if (answer->rm_Result2)
                        DeleteArgstring((char *)answer->rm_Result2);

                DeleteArgstring((char *)ARG0(answer));
                DeleteRexxMsg(answer);
                return(&result);
            }
        }
    }
    Permit();
    return(NULL);
}
///

